Status for Dolphin Central

Recent events

2026-07-18T23:46:09.549628	{'source': 'logging', 'level': 'INFO', 'pathname': '/nix/store/m89a38mxx677zd2j3gqq91c40d1i7dc6-central-env/lib/python3.13/site-packages/central/github/authz.py', 'lineno': 30, 'msg': 'New GH %s: %s', 'args': "('dolphin-emu/core-developers', 'lioncash,Pokechu22,degasus,Helios747,iwubcode,spycrab,linkmauve,skidau,AdmiralCurtiss,Tilka,leoetlino,Parlane,JosJuice,Dentomologist,OatmealDome,phire,CrossVR,delroth,hrydgard,jordan-woyak')", 'type': 'internal_log'}
2026-07-18T23:46:09.277118	{'source': 'logging', 'level': 'INFO', 'pathname': '/nix/store/m89a38mxx677zd2j3gqq91c40d1i7dc6-central-env/lib/python3.13/site-packages/central/github/authz.py', 'lineno': 21, 'msg': 'Refreshing list of trusted users (from %s/%s)', 'args': "('dolphin-emu', 'core-developers')", 'type': 'internal_log'}
2026-07-18T23:45:27.895462	{'source': 'logging', 'level': 'INFO', 'pathname': '/nix/store/m89a38mxx677zd2j3gqq91c40d1i7dc6-central-env/lib/python3.13/site-packages/central/github/authz.py', 'lineno': 30, 'msg': 'New GH %s: %s', 'args': "('dolphin-emu/trusted-developers', 'EmptyChaos,unknownbrackets,CelestialAmber,Ebola16,Geotale,krnlyng,neobrain,CookiePLMonster,degasus,Stevoisiak,LillyJadeKatrin,iwubcode,kamiyo,Filoppi,hthh,rukai,Linkinworm,Parlane,Starsam80,meffij,phire,delroth,vladfi1,zackhow,malleoz,adamdmoss,NanoByte011,randomstuff,lioncash,mrgreywater,cristian64,Ziek,mimimi085181,deReeperJosh,bentley,jezze,orbea,ligfx,tygyh,magumagu,mathieui,skidau,kayru,endrift,jjdelvalle,Tilka,shonumi,Sintendo,Phatcat,TryTwo,marcan,JosJuice,zopieux,Buddybenj,OatmealDome,JoshuaVandaele,Techjar,Simonx22,JMC47,ColinDTaylor,CasualPokePlayer,Lobsterzelda,hrydgard,spxtr,archshift,corwin-mcknight,ShimmerGlass,aroulin,K0bin,LPFaint99,OrN,aldelaro5,skylersaleh,Helios747,CrystalGamma,nickbeth,tom-pratt,spycrab,magcius,RachelBryk,SuperSamus,AdmiralCurtiss,mmastrac,PatrickFerry,gwicks,BhaaLseN,leoetlino,rlnilsen,cscd98,riking,glennricster,Dentomologist,FioraAeterna,jloehr,comex,Linktothepast,galop1n,mandar1jn,RisingFog,moncefmechri,dreamsyntax,jordan-woyak,hdcmeta,MayImilae,Orphis,hackbar,Pokechu22,crediar,Gamer64ytb,booto,linkmauve,Tinob,Zopolis4,nullgemm,Alcaro,smurf3tte,yourWaifu,LAGonauta,sepalani,mitaclaw,JordanTheToaster,noahpistilli,DacoTaco,CrossVR,TellowKrinkle,Hydr8gon,merryhime,mbc07,SirMangler,Sam-Belliveau,mahdihijazi')", 'type': 'internal_log'}
2026-07-18T23:45:26.521607	{'source': 'logging', 'level': 'INFO', 'pathname': '/nix/store/m89a38mxx677zd2j3gqq91c40d1i7dc6-central-env/lib/python3.13/site-packages/central/github/authz.py', 'lineno': 21, 'msg': 'Refreshing list of trusted users (from %s/%s)', 'args': "('dolphin-emu', 'trusted-developers')", 'type': 'internal_log'}
2026-07-18T23:41:40.251881	{'source': 'notifications', 'msg': '[\x1f\x0313dolphin-emu/dolphin\x03\x1f] \x0303t\ufeffhethiny\x03 commented on #14731 (Convert To WBFS Support): \x1f\x0302https://dolp.in/pr14731#issuecomment-5013376425\x03\x1f', 'type': 'notification'}
2026-07-18T23:41:40.251704	{'source': 'webserver', 'gh_type': 'issue_comment', 'raw': {'action': 'created', 'issue': {'url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/14731', 'repository_url': 'https://api.github.com/repos/dolphin-emu/dolphin', 'labels_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/14731/labels{/name}', 'comments_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/14731/comments', 'events_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/14731/events', 'html_url': 'https://github.com/dolphin-emu/dolphin/pull/14731', 'id': 4888393904, 'node_id': 'PR_kwDOALCn2M7x0I-2', 'number': 14731, 'title': 'Convert To WBFS Support', 'user': {'login': 'thethiny', 'id': 6018214, 'node_id': 'MDQ6VXNlcjYwMTgyMTQ=', 'avatar_url': 'https://avatars.githubusercontent.com/u/6018214?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/thethiny', 'html_url': 'https://github.com/thethiny', 'followers_url': 'https://api.github.com/users/thethiny/followers', 'following_url': 'https://api.github.com/users/thethiny/following{/other_user}', 'gists_url': 'https://api.github.com/users/thethiny/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/thethiny/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/thethiny/subscriptions', 'organizations_url': 'https://api.github.com/users/thethiny/orgs', 'repos_url': 'https://api.github.com/users/thethiny/repos', 'events_url': 'https://api.github.com/users/thethiny/events{/privacy}', 'received_events_url': 'https://api.github.com/users/thethiny/received_events', 'type': 'User', 'user_view_type': 'public', 'site_admin': False}, 'labels': [], 'state': 'open', 'locked': False, 'assignees': [], 'milestone': None, 'comments': 43, 'created_at': '2026-07-15T01:16:25Z', 'updated_at': '2026-07-18T23:41:38Z', 'closed_at': None, 'assignee': None, 'author_association': 'NONE', 'issue_field_values': [], 'type': None, 'active_lock_reason': None, 'draft': False, 'pull_request': {'url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/14731', 'html_url': 'https://github.com/dolphin-emu/dolphin/pull/14731', 'diff_url': 'https://github.com/dolphin-emu/dolphin/pull/14731.diff', 'patch_url': 'https://github.com/dolphin-emu/dolphin/pull/14731.patch', 'merged_at': None}, 'body': "This PR introduces Conversion **to** WBFS support. WBFS is the format that is used by USB Loaders on a real Wii device.\r\n\r\n## Design decisions & hardcoded values\r\nThe writer uses fixed sector sizes that match what [libwbfs (the reference implementation by kwiirk)](https://github.com/kwiirk/wbfs/blob/master/libwbfs/libwbfs.c#L128-L134) computes for a standard single-layer Wii disc. These 2 hardcodes are stable and work correctly across all my testings.\r\n- HD sector shift: 9 (512 bytes)\r\n- WBFS sector shift: 21 (2 MiB)\r\nThese are not configurable via the UI. All existing WBFS tools use these values, and since the aim is to support USB Loaders then this has been tested and it is working on a real Wii.\r\n\r\nConverting from WBFS is not enabled. The existing `WbfsFileReader` reports `DataSizeType::UpperBound`, and `ShouldAllowConversion()` requires `Accurate`. I am able to support this but since it was hardcoded by the Dolphin team I thought a discussion is warranted.\r\n\r\n## Testing\r\n- Verified with DolphinTool header and DolphinTool verify\r\n- Verified with wit FILETYPE and wit DUMP (Wiimm's ISO Tools recognizes valid WBFS structure, partitions, encryption)\r\n- Tested ISO to WBFS and RVZ to WBFS conversions\r\n- Output file sizes match Wii Backup Manager when scrubbing is enabled (~0.1% difference), works when scrubbing is disabled.\r\n- Output WBFS files play correctly in Dolphin\r\n- Output WBFS files play correctly on a real Wii using USB Loader GX e25c4f3\r\n", 'reactions': {'url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/14731/reactions', 'total_count': 2, '+1': 2, '-1': 0, 'laugh': 0, 'hooray': 0, 'confused': 0, 'heart': 0, 'rocket': 0, 'eyes': 0}, 'timeline_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/14731/timeline', 'performed_via_github_app': None, 'state_reason': None}, 'comment': {'url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/comments/5013376425', 'html_url': 'https://github.com/dolphin-emu/dolphin/pull/14731#issuecomment-5013376425', 'issue_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/14731', 'id': 5013376425, 'node_id': 'IC_kwDOALCn2M8AAAABKtINqQ', 'user': {'login': 'thethiny', 'id': 6018214, 'node_id': 'MDQ6VXNlcjYwMTgyMTQ=', 'avatar_url': 'https://avatars.githubusercontent.com/u/6018214?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/thethiny', 'html_url': 'https://github.com/thethiny', 'followers_url': 'https://api.github.com/users/thethiny/followers', 'following_url': 'https://api.github.com/users/thethiny/following{/other_user}', 'gists_url': 'https://api.github.com/users/thethiny/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/thethiny/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/thethiny/subscriptions', 'organizations_url': 'https://api.github.com/users/thethiny/orgs', 'repos_url': 'https://api.github.com/users/thethiny/repos', 'events_url': 'https://api.github.com/users/thethiny/events{/privacy}', 'received_events_url': 'https://api.github.com/users/thethiny/received_events', 'type': 'User', 'user_view_type': 'public', 'site_admin': False}, 'created_at': '2026-07-18T23:41:38Z', 'updated_at': '2026-07-18T23:41:38Z', 'body': "> I'm not sure about NKitHeader. Certainly better, and probably good enough to merge. But it now feels a little bloated, violates DRY.\r\n> \r\n> Maybe the flags would be better handled with `Common::BitStruct`? And some kind of template approach might be better for the Optional fields.\r\n\r\nThe question here would be, do we lose clarity for DRY? Because we are able to compact the 5 structs into a template but then ReadField hides the bounds check and memcpy behind a generic function, making it less immediately obvious what's happening at each step. Let me know which approach to take, meanwhile I will be implementing your changes.", 'author_association': 'NONE', 'reactions': {'url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/comments/5013376425/reactions', 'total_count': 0, '+1': 0, '-1': 0, 'laugh': 0, 'hooray': 0, 'confused': 0, 'heart': 0, 'rocket': 0, 'eyes': 0}, 'performed_via_github_app': None, 'minimized': None}, 'repository': {'id': 11577304, 'node_id': 'MDEwOlJlcG9zaXRvcnkxMTU3NzMwNA==', 'name': 'dolphin', 'full_name': 'dolphin-emu/dolphin', 'private': False, 'owner': {'login': 'dolphin-emu', 'id': 5050316, 'node_id': 'MDEyOk9yZ2FuaXphdGlvbjUwNTAzMTY=', 'avatar_url': 'https://avatars.githubusercontent.com/u/5050316?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/dolphin-emu', 'html_url': 'https://github.com/dolphin-emu', 'followers_url': 'https://api.github.com/users/dolphin-emu/followers', 'following_url': 'https://api.github.com/users/dolphin-emu/following{/other_user}', 'gists_url': 'https://api.github.com/users/dolphin-emu/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/dolphin-emu/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/dolphin-emu/subscriptions', 'organizations_url': 'https://api.github.com/users/dolphin-emu/orgs', 'repos_url': 'https://api.github.com/users/dolphin-emu/repos', 'events_url': 'https://api.github.com/users/dolphin-emu/events{/privacy}', 'received_events_url': 'https://api.github.com/users/dolphin-emu/received_events', 'type': 'Organization', 'user_view_type': 'public', 'site_admin': False}, 'html_url': 'https://github.com/dolphin-emu/dolphin', 'description': 'Dolphin is a GameCube / Wii emulator, allowing you to play games for these two platforms on PC with improvements.', 'fork': False, 'url': 'https://api.github.com/repos/dolphin-emu/dolphin', 'forks_url': 'https://api.github.com/repos/dolphin-emu/dolphin/forks', 'keys_url': 'https://api.github.com/repos/dolphin-emu/dolphin/keys{/key_id}', 'collaborators_url': 'https://api.github.com/repos/dolphin-emu/dolphin/collaborators{/collaborator}', 'teams_url': 'https://api.github.com/repos/dolphin-emu/dolphin/teams', 'hooks_url': 'https://api.github.com/repos/dolphin-emu/dolphin/hooks', 'issue_events_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/events{/number}', 'events_url': 'https://api.github.com/repos/dolphin-emu/dolphin/events', 'assignees_url': 'https://api.github.com/repos/dolphin-emu/dolphin/assignees{/user}', 'branches_url': 'https://api.github.com/repos/dolphin-emu/dolphin/branches{/branch}', 'tags_url': 'https://api.github.com/repos/dolphin-emu/dolphin/tags', 'blobs_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/blobs{/sha}', 'git_tags_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/tags{/sha}', 'git_refs_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/refs{/sha}', 'trees_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/trees{/sha}', 'statuses_url': 'https://api.github.com/repos/dolphin-emu/dolphin/statuses/{sha}', 'languages_url': 'https://api.github.com/repos/dolphin-emu/dolphin/languages', 'stargazers_url': 'https://api.github.com/repos/dolphin-emu/dolphin/stargazers', 'contributors_url': 'https://api.github.com/repos/dolphin-emu/dolphin/contributors', 'subscribers_url': 'https://api.github.com/repos/dolphin-emu/dolphin/subscribers', 'subscription_url': 'https://api.github.com/repos/dolphin-emu/dolphin/subscription', 'commits_url': 'https://api.github.com/repos/dolphin-emu/dolphin/commits{/sha}', 'git_commits_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/commits{/sha}', 'comments_url': 'https://api.github.com/repos/dolphin-emu/dolphin/comments{/number}', 'issue_comment_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/comments{/number}', 'contents_url': 'https://api.github.com/repos/dolphin-emu/dolphin/contents/{+path}', 'compare_url': 'https://api.github.com/repos/dolphin-emu/dolphin/compare/{base}...{head}', 'merges_url': 'https://api.github.com/repos/dolphin-emu/dolphin/merges', 'archive_url': 'https://api.github.com/repos/dolphin-emu/dolphin/{archive_format}{/ref}', 'downloads_url': 'https://api.github.com/repos/dolphin-emu/dolphin/downloads', 'issues_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues{/number}', 'pulls_url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls{/number}', 'milestones_url': 'https://api.github.com/repos/dolphin-emu/dolphin/milestones{/number}', 'notifications_url': 'https://api.github.com/repos/dolphin-emu/dolphin/notifications{?since,all,participating}', 'labels_url': 'https://api.github.com/repos/dolphin-emu/dolphin/labels{/name}', 'releases_url': 'https://api.github.com/repos/dolphin-emu/dolphin/releases{/id}', 'deployments_url': 'https://api.github.com/repos/dolphin-emu/dolphin/deployments', 'created_at': '2013-07-22T09:07:57Z', 'updated_at': '2026-07-18T23:13:54Z', 'pushed_at': '2026-07-18T10:34:54Z', 'git_url': 'git://github.com/dolphin-emu/dolphin.git', 'ssh_url': 'git@github.com:dolphin-emu/dolphin.git', 'clone_url': 'https://github.com/dolphin-emu/dolphin.git', 'svn_url': 'https://github.com/dolphin-emu/dolphin', 'homepage': 'https://dolphin-emu.org', 'size': 558448, 'stargazers_count': 15273, 'watchers_count': 15273, 'language': 'C++', 'has_issues': False, 'has_projects': False, 'has_downloads': True, 'has_wiki': True, 'has_pages': False, 'has_discussions': False, 'forks_count': 3162, 'mirror_url': None, 'archived': False, 'disabled': False, 'open_issues_count': 446, 'license': {'key': 'other', 'name': 'Other', 'spdx_id': 'NOASSERTION', 'url': None, 'node_id': 'MDc6TGljZW5zZTA='}, 'allow_forking': True, 'is_template': False, 'web_commit_signoff_required': False, 'has_pull_requests': True, 'pull_request_creation_policy': 'all', 'topics': ['cpp', 'emulation', 'emulator', 'gamecube', 'wii'], 'visibility': 'public', 'forks': 3162, 'open_issues': 446, 'watchers': 15273, 'default_branch': 'master', 'custom_properties': {}}, 'organization': {'login': 'dolphin-emu', 'id': 5050316, 'node_id': 'MDEyOk9yZ2FuaXphdGlvbjUwNTAzMTY=', 'url': 'https://api.github.com/orgs/dolphin-emu', 'repos_url': 'https://api.github.com/orgs/dolphin-emu/repos', 'events_url': 'https://api.github.com/orgs/dolphin-emu/events', 'hooks_url': 'https://api.github.com/orgs/dolphin-emu/hooks', 'issues_url': 'https://api.github.com/orgs/dolphin-emu/issues', 'members_url': 'https://api.github.com/orgs/dolphin-emu/members{/member}', 'public_members_url': 'https://api.github.com/orgs/dolphin-emu/public_members{/member}', 'avatar_url': 'https://avatars.githubusercontent.com/u/5050316?v=4', 'description': ''}, 'sender': {'login': 'thethiny', 'id': 6018214, 'node_id': 'MDQ6VXNlcjYwMTgyMTQ=', 'avatar_url': 'https://avatars.githubusercontent.com/u/6018214?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/thethiny', 'html_url': 'https://github.com/thethiny', 'followers_url': 'https://api.github.com/users/thethiny/followers', 'following_url': 'https://api.github.com/users/thethiny/following{/other_user}', 'gists_url': 'https://api.github.com/users/thethiny/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/thethiny/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/thethiny/subscriptions', 'organizations_url': 'https://api.github.com/users/thethiny/orgs', 'repos_url': 'https://api.github.com/users/thethiny/repos', 'events_url': 'https://api.github.com/users/thethiny/events{/privacy}', 'received_events_url': 'https://api.github.com/users/thethiny/received_events', 'type': 'User', 'user_view_type': 'public', 'site_admin': False}, 'installation': {'id': 35437981, 'node_id': 'MDIzOkludGVncmF0aW9uSW5zdGFsbGF0aW9uMzU0Mzc5ODE='}}, 'type': 'raw_gh_hook'}
2026-07-18T23:41:40.251674	{'source': 'ghhookparser', 'repo': 'dolphin-emu/dolphin', 'author': 'thethiny', 'action': 'created', 'id': 14731, 'title': 'Convert To WBFS Support', 'url': 'https://github.com/dolphin-emu/dolphin/pull/14731#issuecomment-5013376425', 'safe_author': False, 'body': "> I'm not sure about NKitHeader. Certainly better, and probably good enough to merge. But it now feels a little bloated, violates DRY.\r\n> \r\n> Maybe the flags would be better handled with `Common::BitStruct`? And some kind of template approach might be better for the Optional fields.\r\n\r\nThe question here would be, do we lose clarity for DRY? Because we are able to compact the 5 structs into a template but then ReadField hides the bounds check and memcpy behind a generic function, making it less immediately obvious what's happening at each step. Let me know which approach to take, meanwhile I will be implementing your changes.", 'raw': {'action': 'created', 'issue': {'url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/14731', 'repository_url': 'https://api.github.com/repos/dolphin-emu/dolphin', 'labels_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/14731/labels{/name}', 'comments_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/14731/comments', 'events_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/14731/events', 'html_url': 'https://github.com/dolphin-emu/dolphin/pull/14731', 'id': 4888393904, 'node_id': 'PR_kwDOALCn2M7x0I-2', 'number': 14731, 'title': 'Convert To WBFS Support', 'user': {'login': 'thethiny', 'id': 6018214, 'node_id': 'MDQ6VXNlcjYwMTgyMTQ=', 'avatar_url': 'https://avatars.githubusercontent.com/u/6018214?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/thethiny', 'html_url': 'https://github.com/thethiny', 'followers_url': 'https://api.github.com/users/thethiny/followers', 'following_url': 'https://api.github.com/users/thethiny/following{/other_user}', 'gists_url': 'https://api.github.com/users/thethiny/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/thethiny/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/thethiny/subscriptions', 'organizations_url': 'https://api.github.com/users/thethiny/orgs', 'repos_url': 'https://api.github.com/users/thethiny/repos', 'events_url': 'https://api.github.com/users/thethiny/events{/privacy}', 'received_events_url': 'https://api.github.com/users/thethiny/received_events', 'type': 'User', 'user_view_type': 'public', 'site_admin': False}, 'labels': [], 'state': 'open', 'locked': False, 'assignees': [], 'milestone': None, 'comments': 43, 'created_at': '2026-07-15T01:16:25Z', 'updated_at': '2026-07-18T23:41:38Z', 'closed_at': None, 'assignee': None, 'author_association': 'NONE', 'issue_field_values': [], 'type': None, 'active_lock_reason': None, 'draft': False, 'pull_request': {'url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/14731', 'html_url': 'https://github.com/dolphin-emu/dolphin/pull/14731', 'diff_url': 'https://github.com/dolphin-emu/dolphin/pull/14731.diff', 'patch_url': 'https://github.com/dolphin-emu/dolphin/pull/14731.patch', 'merged_at': None}, 'body': "This PR introduces Conversion **to** WBFS support. WBFS is the format that is used by USB Loaders on a real Wii device.\r\n\r\n## Design decisions & hardcoded values\r\nThe writer uses fixed sector sizes that match what [libwbfs (the reference implementation by kwiirk)](https://github.com/kwiirk/wbfs/blob/master/libwbfs/libwbfs.c#L128-L134) computes for a standard single-layer Wii disc. These 2 hardcodes are stable and work correctly across all my testings.\r\n- HD sector shift: 9 (512 bytes)\r\n- WBFS sector shift: 21 (2 MiB)\r\nThese are not configurable via the UI. All existing WBFS tools use these values, and since the aim is to support USB Loaders then this has been tested and it is working on a real Wii.\r\n\r\nConverting from WBFS is not enabled. The existing `WbfsFileReader` reports `DataSizeType::UpperBound`, and `ShouldAllowConversion()` requires `Accurate`. I am able to support this but since it was hardcoded by the Dolphin team I thought a discussion is warranted.\r\n\r\n## Testing\r\n- Verified with DolphinTool header and DolphinTool verify\r\n- Verified with wit FILETYPE and wit DUMP (Wiimm's ISO Tools recognizes valid WBFS structure, partitions, encryption)\r\n- Tested ISO to WBFS and RVZ to WBFS conversions\r\n- Output file sizes match Wii Backup Manager when scrubbing is enabled (~0.1% difference), works when scrubbing is disabled.\r\n- Output WBFS files play correctly in Dolphin\r\n- Output WBFS files play correctly on a real Wii using USB Loader GX e25c4f3\r\n", 'reactions': {'url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/14731/reactions', 'total_count': 2, '+1': 2, '-1': 0, 'laugh': 0, 'hooray': 0, 'confused': 0, 'heart': 0, 'rocket': 0, 'eyes': 0}, 'timeline_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/14731/timeline', 'performed_via_github_app': None, 'state_reason': None}, 'comment': {'url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/comments/5013376425', 'html_url': 'https://github.com/dolphin-emu/dolphin/pull/14731#issuecomment-5013376425', 'issue_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/14731', 'id': 5013376425, 'node_id': 'IC_kwDOALCn2M8AAAABKtINqQ', 'user': {'login': 'thethiny', 'id': 6018214, 'node_id': 'MDQ6VXNlcjYwMTgyMTQ=', 'avatar_url': 'https://avatars.githubusercontent.com/u/6018214?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/thethiny', 'html_url': 'https://github.com/thethiny', 'followers_url': 'https://api.github.com/users/thethiny/followers', 'following_url': 'https://api.github.com/users/thethiny/following{/other_user}', 'gists_url': 'https://api.github.com/users/thethiny/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/thethiny/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/thethiny/subscriptions', 'organizations_url': 'https://api.github.com/users/thethiny/orgs', 'repos_url': 'https://api.github.com/users/thethiny/repos', 'events_url': 'https://api.github.com/users/thethiny/events{/privacy}', 'received_events_url': 'https://api.github.com/users/thethiny/received_events', 'type': 'User', 'user_view_type': 'public', 'site_admin': False}, 'created_at': '2026-07-18T23:41:38Z', 'updated_at': '2026-07-18T23:41:38Z', 'body': "> I'm not sure about NKitHeader. Certainly better, and probably good enough to merge. But it now feels a little bloated, violates DRY.\r\n> \r\n> Maybe the flags would be better handled with `Common::BitStruct`? And some kind of template approach might be better for the Optional fields.\r\n\r\nThe question here would be, do we lose clarity for DRY? Because we are able to compact the 5 structs into a template but then ReadField hides the bounds check and memcpy behind a generic function, making it less immediately obvious what's happening at each step. Let me know which approach to take, meanwhile I will be implementing your changes.", 'author_association': 'NONE', 'reactions': {'url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/comments/5013376425/reactions', 'total_count': 0, '+1': 0, '-1': 0, 'laugh': 0, 'hooray': 0, 'confused': 0, 'heart': 0, 'rocket': 0, 'eyes': 0}, 'performed_via_github_app': None, 'minimized': None}, 'repository': {'id': 11577304, 'node_id': 'MDEwOlJlcG9zaXRvcnkxMTU3NzMwNA==', 'name': 'dolphin', 'full_name': 'dolphin-emu/dolphin', 'private': False, 'owner': {'login': 'dolphin-emu', 'id': 5050316, 'node_id': 'MDEyOk9yZ2FuaXphdGlvbjUwNTAzMTY=', 'avatar_url': 'https://avatars.githubusercontent.com/u/5050316?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/dolphin-emu', 'html_url': 'https://github.com/dolphin-emu', 'followers_url': 'https://api.github.com/users/dolphin-emu/followers', 'following_url': 'https://api.github.com/users/dolphin-emu/following{/other_user}', 'gists_url': 'https://api.github.com/users/dolphin-emu/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/dolphin-emu/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/dolphin-emu/subscriptions', 'organizations_url': 'https://api.github.com/users/dolphin-emu/orgs', 'repos_url': 'https://api.github.com/users/dolphin-emu/repos', 'events_url': 'https://api.github.com/users/dolphin-emu/events{/privacy}', 'received_events_url': 'https://api.github.com/users/dolphin-emu/received_events', 'type': 'Organization', 'user_view_type': 'public', 'site_admin': False}, 'html_url': 'https://github.com/dolphin-emu/dolphin', 'description': 'Dolphin is a GameCube / Wii emulator, allowing you to play games for these two platforms on PC with improvements.', 'fork': False, 'url': 'https://api.github.com/repos/dolphin-emu/dolphin', 'forks_url': 'https://api.github.com/repos/dolphin-emu/dolphin/forks', 'keys_url': 'https://api.github.com/repos/dolphin-emu/dolphin/keys{/key_id}', 'collaborators_url': 'https://api.github.com/repos/dolphin-emu/dolphin/collaborators{/collaborator}', 'teams_url': 'https://api.github.com/repos/dolphin-emu/dolphin/teams', 'hooks_url': 'https://api.github.com/repos/dolphin-emu/dolphin/hooks', 'issue_events_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/events{/number}', 'events_url': 'https://api.github.com/repos/dolphin-emu/dolphin/events', 'assignees_url': 'https://api.github.com/repos/dolphin-emu/dolphin/assignees{/user}', 'branches_url': 'https://api.github.com/repos/dolphin-emu/dolphin/branches{/branch}', 'tags_url': 'https://api.github.com/repos/dolphin-emu/dolphin/tags', 'blobs_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/blobs{/sha}', 'git_tags_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/tags{/sha}', 'git_refs_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/refs{/sha}', 'trees_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/trees{/sha}', 'statuses_url': 'https://api.github.com/repos/dolphin-emu/dolphin/statuses/{sha}', 'languages_url': 'https://api.github.com/repos/dolphin-emu/dolphin/languages', 'stargazers_url': 'https://api.github.com/repos/dolphin-emu/dolphin/stargazers', 'contributors_url': 'https://api.github.com/repos/dolphin-emu/dolphin/contributors', 'subscribers_url': 'https://api.github.com/repos/dolphin-emu/dolphin/subscribers', 'subscription_url': 'https://api.github.com/repos/dolphin-emu/dolphin/subscription', 'commits_url': 'https://api.github.com/repos/dolphin-emu/dolphin/commits{/sha}', 'git_commits_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/commits{/sha}', 'comments_url': 'https://api.github.com/repos/dolphin-emu/dolphin/comments{/number}', 'issue_comment_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/comments{/number}', 'contents_url': 'https://api.github.com/repos/dolphin-emu/dolphin/contents/{+path}', 'compare_url': 'https://api.github.com/repos/dolphin-emu/dolphin/compare/{base}...{head}', 'merges_url': 'https://api.github.com/repos/dolphin-emu/dolphin/merges', 'archive_url': 'https://api.github.com/repos/dolphin-emu/dolphin/{archive_format}{/ref}', 'downloads_url': 'https://api.github.com/repos/dolphin-emu/dolphin/downloads', 'issues_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues{/number}', 'pulls_url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls{/number}', 'milestones_url': 'https://api.github.com/repos/dolphin-emu/dolphin/milestones{/number}', 'notifications_url': 'https://api.github.com/repos/dolphin-emu/dolphin/notifications{?since,all,participating}', 'labels_url': 'https://api.github.com/repos/dolphin-emu/dolphin/labels{/name}', 'releases_url': 'https://api.github.com/repos/dolphin-emu/dolphin/releases{/id}', 'deployments_url': 'https://api.github.com/repos/dolphin-emu/dolphin/deployments', 'created_at': '2013-07-22T09:07:57Z', 'updated_at': '2026-07-18T23:13:54Z', 'pushed_at': '2026-07-18T10:34:54Z', 'git_url': 'git://github.com/dolphin-emu/dolphin.git', 'ssh_url': 'git@github.com:dolphin-emu/dolphin.git', 'clone_url': 'https://github.com/dolphin-emu/dolphin.git', 'svn_url': 'https://github.com/dolphin-emu/dolphin', 'homepage': 'https://dolphin-emu.org', 'size': 558448, 'stargazers_count': 15273, 'watchers_count': 15273, 'language': 'C++', 'has_issues': False, 'has_projects': False, 'has_downloads': True, 'has_wiki': True, 'has_pages': False, 'has_discussions': False, 'forks_count': 3162, 'mirror_url': None, 'archived': False, 'disabled': False, 'open_issues_count': 446, 'license': {'key': 'other', 'name': 'Other', 'spdx_id': 'NOASSERTION', 'url': None, 'node_id': 'MDc6TGljZW5zZTA='}, 'allow_forking': True, 'is_template': False, 'web_commit_signoff_required': False, 'has_pull_requests': True, 'pull_request_creation_policy': 'all', 'topics': ['cpp', 'emulation', 'emulator', 'gamecube', 'wii'], 'visibility': 'public', 'forks': 3162, 'open_issues': 446, 'watchers': 15273, 'default_branch': 'master', 'custom_properties': {}}, 'organization': {'login': 'dolphin-emu', 'id': 5050316, 'node_id': 'MDEyOk9yZ2FuaXphdGlvbjUwNTAzMTY=', 'url': 'https://api.github.com/orgs/dolphin-emu', 'repos_url': 'https://api.github.com/orgs/dolphin-emu/repos', 'events_url': 'https://api.github.com/orgs/dolphin-emu/events', 'hooks_url': 'https://api.github.com/orgs/dolphin-emu/hooks', 'issues_url': 'https://api.github.com/orgs/dolphin-emu/issues', 'members_url': 'https://api.github.com/orgs/dolphin-emu/members{/member}', 'public_members_url': 'https://api.github.com/orgs/dolphin-emu/public_members{/member}', 'avatar_url': 'https://avatars.githubusercontent.com/u/5050316?v=4', 'description': ''}, 'sender': {'login': 'thethiny', 'id': 6018214, 'node_id': 'MDQ6VXNlcjYwMTgyMTQ=', 'avatar_url': 'https://avatars.githubusercontent.com/u/6018214?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/thethiny', 'html_url': 'https://github.com/thethiny', 'followers_url': 'https://api.github.com/users/thethiny/followers', 'following_url': 'https://api.github.com/users/thethiny/following{/other_user}', 'gists_url': 'https://api.github.com/users/thethiny/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/thethiny/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/thethiny/subscriptions', 'organizations_url': 'https://api.github.com/users/thethiny/orgs', 'repos_url': 'https://api.github.com/users/thethiny/repos', 'events_url': 'https://api.github.com/users/thethiny/events{/privacy}', 'received_events_url': 'https://api.github.com/users/thethiny/received_events', 'type': 'User', 'user_view_type': 'public', 'site_admin': False}, 'installation': {'id': 35437981, 'node_id': 'MDIzOkludGVncmF0aW9uSW5zdGFsbGF0aW9uMzU0Mzc5ODE='}}, 'type': 'gh_issue_comment'}
2026-07-18T23:41:29.025116	{'source': 'notifications', 'msg': '[\x1f\x0313dolphin-emu/dolphin\x03\x1f] \x0303p\ufeffhire\x03 commented on #14731 24b41d: \x1f\x0302https://dolp.in/pr14731#discussion_r3609425504\x03\x1f', 'type': 'notification'}
2026-07-18T23:41:29.024934	{'source': 'webserver', 'gh_type': 'pull_request_review_comment', 'raw': {'action': 'created', 'comment': {'url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/comments/3609425504', 'pull_request_review_id': 4729506940, 'id': 3609425504, 'node_id': 'PRRC_kwDOALCn2M7XI3Zg', 'diff_hunk': '@@ -186,7 +380,304 @@ std::unique_ptr<WbfsFileReader> WbfsFileReader::Create(File::DirectIOFile file,\n   if (!reader->IsGood())\n     reader.reset();\n \n+  if (reader && reader->m_has_nkit_header)\n+    reader->ReadPartitionInfo();\n+\n   return reader;\n }\n \n+// Converts any disc image to WBFS with an NKit v2 header for lossless round-trips.\n+// Strips disc-level junk and partition-level junk (encrypted sectors whose decrypted\n+// content is zero or LFG padding), records a junk bitmap for reconstruction.\n+// See: https://github.com/dolphin-emu/dolphin/pull/14731\n+bool ConvertToWBFS(BlobReader* infile, const std::string& infile_path,\n+                   const std::string& outfile_path, const CompressCB& callback)\n+{\n+  ASSERT(infile->GetDataSizeType() == DataSizeType::Accurate ||\n+         infile->GetDataSizeType() == DataSizeType::UpperBound);\n+\n+  File::DirectIOFile outfile(outfile_path, File::AccessMode::Write);\n+  if (!outfile.IsOpen())\n+  {\n+    PanicAlertFmtT(\n+        "Failed to open the output file \\"{0}\\".\\n"\n+        "Check that you have permissions to write the target folder and that the media can "\n+        "be written.",\n+        outfile_path);\n+    return false;\n+  }\n+\n+  const u64 disc_size = infile->GetDataSize();\n+\n+  // These match the values used by standard WBFS tools (wwt, WBFS Manager)\n+  static constexpr u8 hd_sector_shift = 9;\n+  static constexpr u8 wbfs_sector_shift = 21;\n+  static constexpr u64 hd_sector_size = 1ull << hd_sector_shift;\n+  static constexpr u64 wbfs_sector_size = 1ull << wbfs_sector_shift;\n+\n+  const u64 blocks_per_disc = (disc_size + wbfs_sector_size - 1) / wbfs_sector_size;\n+  const u64 disc_info_size =\n+      Common::AlignUp(WII_DISC_HEADER_SIZE + blocks_per_disc * sizeof(u16), hd_sector_size);\n+\n+  // Read disc header (first 256 bytes contain disc_id, disc_num, title, etc.)\n+  std::vector<u8> disc_header(WII_DISC_HEADER_SIZE, 0);\n+  if (!infile->Read(0, WII_DISC_HEADER_SIZE, disc_header.data()))\n+  {\n+    PanicAlertFmtT("Failed to read from the input file \\"{0}\\".", infile_path);\n+    return false;\n+  }\n+\n+  // Use Volume for partition info and decrypted reads\n+  struct PartitionInfo\n+  {\n+    u64 data_offset;\n+    u64 data_size;\n+    Partition partition;\n+  };\n+  std::vector<PartitionInfo> partitions;\n+\n+  std::unique_ptr<VolumeDisc> volume = CreateDisc(infile_path);\n+  if (volume)\n+  {\n+    for (const Partition& partition : volume->GetPartitions())\n+    {\n+      const std::optional<u64> data_offset =\n+          volume->ReadSwappedAndShifted(partition.offset + 0x2B8, PARTITION_NONE);\n+      const std::optional<u64> data_size =\n+          volume->ReadSwappedAndShifted(partition.offset + 0x2BC, PARTITION_NONE);\n+      if (!data_offset || !data_size)\n+        continue;\n+\n+      PartitionInfo info;\n+      info.data_offset = partition.offset + *data_offset;\n+      info.data_size = *data_size;\n+      info.partition = partition;\n+      partitions.push_back(info);\n+    }\n+  }\n+\n+  // NKit v2 gap type bitmap: 1 bit per block, MSB-first, always sized for dual-layer\n+  const u64 gap_type_blocks = (DL_DVD_SIZE + wbfs_sector_size - 1) / wbfs_sector_size;\n+  const u64 gap_type_bytes = (gap_type_blocks + 7) / 8;\n+  std::vector<u8> gap_type(gap_type_bytes, 0);\n+\n+  // Compute data_start up front so we can write sectors during the scan\n+  const u64 data_start = Common::AlignUp(hd_sector_size + disc_info_size, wbfs_sector_size);\n+  const u16 wlba_base = static_cast<u16>(data_start / wbfs_sector_size);\n+\n+  // Single pass: scan, classify, hash, and write used sectors in one loop\n+  std::vector<u8> sector_buf(wbfs_sector_size, 0);\n+  std::vector<u16> wlba_table(blocks_per_disc, 0);\n+  u16 used_count = 0;\n+\n+  // NKit v2 stores four hash digests for verification\n+  auto sha1_ctx = Common::SHA1::CreateContext();\n+  u32 crc = Common::StartCRC32();\n+  mbedtls_md5_context md5_ctx{};\n+  mbedtls_md5_init(&md5_ctx);\n+  mbedtls_md5_starts_ret(&md5_ctx);\n+  XXH64_state_t* xxh_state = XXH64_createState();\n+  XXH64_reset(xxh_state, 0);\n+\n+  for (u64 i = 0; i < blocks_per_disc; i++)\n+  {\n+    if (i % 100 == 0)\n+    {\n+      const bool was_cancelled =\n+          !callback(Common::GetStringT("Converting"),\n+                    static_cast<float>(i) / static_cast<float>(blocks_per_disc));\n+      if (was_cancelled)\n+      {\n+        XXH64_freeState(xxh_state);\n+        mbedtls_md5_free(&md5_ctx);\n+        outfile.Close();\n+        File::Delete(outfile_path);\n+        return false;\n+      }\n+    }\n+\n+    const u64 offset = i * wbfs_sector_size;\n+    const size_t sz = static_cast<size_t>(std::min(wbfs_sector_size, disc_size - offset));\n+\n+    if (!infile->Read(offset, sz, sector_buf.data()))', 'path': 'Source/Core/DiscIO/WbfsBlob.cpp', 'commit_id': '24b41d58df2315831b74f76b95417f2739d02f9d', 'original_commit_id': '24b41d58df2315831b74f76b95417f2739d02f9d', 'user': {'login': 'phire', 'id': 138484, 'node_id': 'MDQ6VXNlcjEzODQ4NA==', 'avatar_url': 'https://avatars.githubusercontent.com/u/138484?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/phire', 'html_url': 'https://github.com/phire', 'followers_url': 'https://api.github.com/users/phire/followers', 'following_url': 'https://api.github.com/users/phire/following{/other_user}', 'gists_url': 'https://api.github.com/users/phire/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/phire/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/phire/subscriptions', 'organizations_url': 'https://api.github.com/users/phire/orgs', 'repos_url': 'https://api.github.com/users/phire/repos', 'events_url': 'https://api.github.com/users/phire/events{/privacy}', 'received_events_url': 'https://api.github.com/users/phire/received_events', 'type': 'User', 'user_view_type': 'public', 'site_admin': False}, 'body': 'Oh... I forgot about the digests. Guess we do need it. ', 'created_at': '2026-07-18T23:41:27Z', 'updated_at': '2026-07-18T23:41:27Z', 'html_url': 'https://github.com/dolphin-emu/dolphin/pull/14731#discussion_r3609425504', 'pull_request_url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/14731', '_links': {'self': {'href': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/comments/3609425504'}, 'html': {'href': 'https://github.com/dolphin-emu/dolphin/pull/14731#discussion_r3609425504'}, 'pull_request': {'href': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/14731'}}, 'reactions': {'url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/comments/3609425504/reactions', 'total_count': 0, '+1': 0, '-1': 0, 'laugh': 0, 'hooray': 0, 'confused': 0, 'heart': 0, 'rocket': 0, 'eyes': 0}, 'start_line': None, 'original_start_line': None, 'start_side': None, 'line': 502, 'original_line': 502, 'side': 'RIGHT', 'in_reply_to_id': 3609251889, 'author_association': 'MEMBER', 'original_position': 409, 'position': 409, 'subject_type': 'line'}, 'pull_request': {'url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/14731', 'id': 4056977334, 'node_id': 'PR_kwDOALCn2M7x0I-2', 'html_url': 'https://github.com/dolphin-emu/dolphin/pull/14731', 'diff_url': 'https://github.com/dolphin-emu/dolphin/pull/14731.diff', 'patch_url': 'https://github.com/dolphin-emu/dolphin/pull/14731.patch', 'issue_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/14731', 'number': 14731, 'state': 'open', 'locked': False, 'title': 'Convert To WBFS Support', 'user': {'login': 'thethiny', 'id': 6018214, 'node_id': 'MDQ6VXNlcjYwMTgyMTQ=', 'avatar_url': 'https://avatars.githubusercontent.com/u/6018214?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/thethiny', 'html_url': 'https://github.com/thethiny', 'followers_url': 'https://api.github.com/users/thethiny/followers', 'following_url': 'https://api.github.com/users/thethiny/following{/other_user}', 'gists_url': 'https://api.github.com/users/thethiny/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/thethiny/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/thethiny/subscriptions', 'organizations_url': 'https://api.github.com/users/thethiny/orgs', 'repos_url': 'https://api.github.com/users/thethiny/repos', 'events_url': 'https://api.github.com/users/thethiny/events{/privacy}', 'received_events_url': 'https://api.github.com/users/thethiny/received_events', 'type': 'User', 'user_view_type': 'public', 'site_admin': False}, 'body': "This PR introduces Conversion **to** WBFS support. WBFS is the format that is used by USB Loaders on a real Wii device.\r\n\r\n## Design decisions & hardcoded values\r\nThe writer uses fixed sector sizes that match what [libwbfs (the reference implementation by kwiirk)](https://github.com/kwiirk/wbfs/blob/master/libwbfs/libwbfs.c#L128-L134) computes for a standard single-layer Wii disc. These 2 hardcodes are stable and work correctly across all my testings.\r\n- HD sector shift: 9 (512 bytes)\r\n- WBFS sector shift: 21 (2 MiB)\r\nThese are not configurable via the UI. All existing WBFS tools use these values, and since the aim is to support USB Loaders then this has been tested and it is working on a real Wii.\r\n\r\nConverting from WBFS is not enabled. The existing `WbfsFileReader` reports `DataSizeType::UpperBound`, and `ShouldAllowConversion()` requires `Accurate`. I am able to support this but since it was hardcoded by the Dolphin team I thought a discussion is warranted.\r\n\r\n## Testing\r\n- Verified with DolphinTool header and DolphinTool verify\r\n- Verified with wit FILETYPE and wit DUMP (Wiimm's ISO Tools recognizes valid WBFS structure, partitions, encryption)\r\n- Tested ISO to WBFS and RVZ to WBFS conversions\r\n- Output file sizes match Wii Backup Manager when scrubbing is enabled (~0.1% difference), works when scrubbing is disabled.\r\n- Output WBFS files play correctly in Dolphin\r\n- Output WBFS files play correctly on a real Wii using USB Loader GX e25c4f3\r\n", 'created_at': '2026-07-15T01:16:25Z', 'updated_at': '2026-07-18T23:37:35Z', 'closed_at': None, 'merged_at': None, 'merge_commit_sha': '228f93416dd80eb09da834ad7852c8eaa4d9212b', 'assignees': [], 'requested_reviewers': [], 'requested_teams': [], 'labels': [], 'milestone': None, 'draft': False, 'commits_url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/14731/commits', 'review_comments_url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/14731/comments', 'review_comment_url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/comments{/number}', 'comments_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/14731/comments', 'statuses_url': 'https://api.github.com/repos/dolphin-emu/dolphin/statuses/24b41d58df2315831b74f76b95417f2739d02f9d', 'head': {'label': 'thethiny:wbfs-conversion', 'ref': 'wbfs-conversion', 'sha': '24b41d58df2315831b74f76b95417f2739d02f9d', 'user': {'login': 'thethiny', 'id': 6018214, 'node_id': 'MDQ6VXNlcjYwMTgyMTQ=', 'avatar_url': 'https://avatars.githubusercontent.com/u/6018214?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/thethiny', 'html_url': 'https://github.com/thethiny', 'followers_url': 'https://api.github.com/users/thethiny/followers', 'following_url': 'https://api.github.com/users/thethiny/following{/other_user}', 'gists_url': 'https://api.github.com/users/thethiny/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/thethiny/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/thethiny/subscriptions', 'organizations_url': 'https://api.github.com/users/thethiny/orgs', 'repos_url': 'https://api.github.com/users/thethiny/repos', 'events_url': 'https://api.github.com/users/thethiny/events{/privacy}', 'received_events_url': 'https://api.github.com/users/thethiny/received_events', 'type': 'User', 'user_view_type': 'public', 'site_admin': False}, 'repo': {'id': 1298654395, 'node_id': 'R_kgDOTWfkuw', 'name': 'dolphin', 'full_name': 'thethiny/dolphin', 'private': False, 'owner': {'login': 'thethiny', 'id': 6018214, 'node_id': 'MDQ6VXNlcjYwMTgyMTQ=', 'avatar_url': 'https://avatars.githubusercontent.com/u/6018214?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/thethiny', 'html_url': 'https://github.com/thethiny', 'followers_url': 'https://api.github.com/users/thethiny/followers', 'following_url': 'https://api.github.com/users/thethiny/following{/other_user}', 'gists_url': 'https://api.github.com/users/thethiny/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/thethiny/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/thethiny/subscriptions', 'organizations_url': 'https://api.github.com/users/thethiny/orgs', 'repos_url': 'https://api.github.com/users/thethiny/repos', 'events_url': 'https://api.github.com/users/thethiny/events{/privacy}', 'received_events_url': 'https://api.github.com/users/thethiny/received_events', 'type': 'User', 'user_view_type': 'public', 'site_admin': False}, 'html_url': 'https://github.com/thethiny/dolphin', 'description': 'Dolphin is a GameCube / Wii emulator, allowing you to play games for these two platforms on PC with improvements.', 'fork': True, 'url': 'https://api.github.com/repos/thethiny/dolphin', 'forks_url': 'https://api.github.com/repos/thethiny/dolphin/forks', 'keys_url': 'https://api.github.com/repos/thethiny/dolphin/keys{/key_id}', 'collaborators_url': 'https://api.github.com/repos/thethiny/dolphin/collaborators{/collaborator}', 'teams_url': 'https://api.github.com/repos/thethiny/dolphin/teams', 'hooks_url': 'https://api.github.com/repos/thethiny/dolphin/hooks', 'issue_events_url': 'https://api.github.com/repos/thethiny/dolphin/issues/events{/number}', 'events_url': 'https://api.github.com/repos/thethiny/dolphin/events', 'assignees_url': 'https://api.github.com/repos/thethiny/dolphin/assignees{/user}', 'branches_url': 'https://api.github.com/repos/thethiny/dolphin/branches{/branch}', 'tags_url': 'https://api.github.com/repos/thethiny/dolphin/tags', 'blobs_url': 'https://api.github.com/repos/thethiny/dolphin/git/blobs{/sha}', 'git_tags_url': 'https://api.github.com/repos/thethiny/dolphin/git/tags{/sha}', 'git_refs_url': 'https://api.github.com/repos/thethiny/dolphin/git/refs{/sha}', 'trees_url': 'https://api.github.com/repos/thethiny/dolphin/git/trees{/sha}', 'statuses_url': 'https://api.github.com/repos/thethiny/dolphin/statuses/{sha}', 'languages_url': 'https://api.github.com/repos/thethiny/dolphin/languages', 'stargazers_url': 'https://api.github.com/repos/thethiny/dolphin/stargazers', 'contributors_url': 'https://api.github.com/repos/thethiny/dolphin/contributors', 'subscribers_url': 'https://api.github.com/repos/thethiny/dolphin/subscribers', 'subscription_url': 'https://api.github.com/repos/thethiny/dolphin/subscription', 'commits_url': 'https://api.github.com/repos/thethiny/dolphin/commits{/sha}', 'git_commits_url': 'https://api.github.com/repos/thethiny/dolphin/git/commits{/sha}', 'comments_url': 'https://api.github.com/repos/thethiny/dolphin/comments{/number}', 'issue_comment_url': 'https://api.github.com/repos/thethiny/dolphin/issues/comments{/number}', 'contents_url': 'https://api.github.com/repos/thethiny/dolphin/contents/{+path}', 'compare_url': 'https://api.github.com/repos/thethiny/dolphin/compare/{base}...{head}', 'merges_url': 'https://api.github.com/repos/thethiny/dolphin/merges', 'archive_url': 'https://api.github.com/repos/thethiny/dolphin/{archive_format}{/ref}', 'downloads_url': 'https://api.github.com/repos/thethiny/dolphin/downloads', 'issues_url': 'https://api.github.com/repos/thethiny/dolphin/issues{/number}', 'pulls_url': 'https://api.github.com/repos/thethiny/dolphin/pulls{/number}', 'milestones_url': 'https://api.github.com/repos/thethiny/dolphin/milestones{/number}', 'notifications_url': 'https://api.github.com/repos/thethiny/dolphin/notifications{?since,all,participating}', 'labels_url': 'https://api.github.com/repos/thethiny/dolphin/labels{/name}', 'releases_url': 'https://api.github.com/repos/thethiny/dolphin/releases{/id}', 'deployments_url': 'https://api.github.com/repos/thethiny/dolphin/deployments', 'created_at': '2026-07-12T22:09:13Z', 'updated_at': '2026-07-12T22:09:13Z', 'pushed_at': '2026-07-18T20:35:03Z', 'git_url': 'git://github.com/thethiny/dolphin.git', 'ssh_url': 'git@github.com:thethiny/dolphin.git', 'clone_url': 'https://github.com/thethiny/dolphin.git', 'svn_url': 'https://github.com/thethiny/dolphin', 'homepage': 'https://dolphin-emu.org', 'size': 515471, 'stargazers_count': 0, 'watchers_count': 0, 'language': None, 'has_issues': False, 'has_projects': True, 'has_downloads': True, 'has_wiki': True, 'has_pages': False, 'has_discussions': False, 'forks_count': 0, 'mirror_url': None, 'archived': False, 'disabled': False, 'open_issues_count': 0, 'license': {'key': 'other', 'name': 'Other', 'spdx_id': 'NOASSERTION', 'url': None, 'node_id': 'MDc6TGljZW5zZTA='}, 'allow_forking': True, 'is_template': False, 'web_commit_signoff_required': False, 'has_pull_requests': True, 'pull_request_creation_policy': 'all', 'topics': [], 'visibility': 'public', 'forks': 0, 'open_issues': 0, 'watchers': 0, 'default_branch': 'master', 'allow_squash_merge': True, 'allow_merge_commit': True, 'allow_rebase_merge': True, 'allow_auto_merge': False, 'delete_branch_on_merge': False, 'allow_update_branch': False, 'use_squash_pr_title_as_default': False, 'squash_merge_commit_message': 'COMMIT_MESSAGES', 'squash_merge_commit_title': 'COMMIT_OR_PR_TITLE', 'merge_commit_message': 'PR_TITLE', 'merge_commit_title': 'MERGE_MESSAGE'}}, 'base': {'label': 'dolphin-emu:master', 'ref': 'master', 'sha': 'd3b2943807dd0073f7767947466dd73cccfef319', 'user': {'login': 'dolphin-emu', 'id': 5050316, 'node_id': 'MDEyOk9yZ2FuaXphdGlvbjUwNTAzMTY=', 'avatar_url': 'https://avatars.githubusercontent.com/u/5050316?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/dolphin-emu', 'html_url': 'https://github.com/dolphin-emu', 'followers_url': 'https://api.github.com/users/dolphin-emu/followers', 'following_url': 'https://api.github.com/users/dolphin-emu/following{/other_user}', 'gists_url': 'https://api.github.com/users/dolphin-emu/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/dolphin-emu/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/dolphin-emu/subscriptions', 'organizations_url': 'https://api.github.com/users/dolphin-emu/orgs', 'repos_url': 'https://api.github.com/users/dolphin-emu/repos', 'events_url': 'https://api.github.com/users/dolphin-emu/events{/privacy}', 'received_events_url': 'https://api.github.com/users/dolphin-emu/received_events', 'type': 'Organization', 'user_view_type': 'public', 'site_admin': False}, 'repo': {'id': 11577304, 'node_id': 'MDEwOlJlcG9zaXRvcnkxMTU3NzMwNA==', 'name': 'dolphin', 'full_name': 'dolphin-emu/dolphin', 'private': False, 'owner': {'login': 'dolphin-emu', 'id': 5050316, 'node_id': 'MDEyOk9yZ2FuaXphdGlvbjUwNTAzMTY=', 'avatar_url': 'https://avatars.githubusercontent.com/u/5050316?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/dolphin-emu', 'html_url': 'https://github.com/dolphin-emu', 'followers_url': 'https://api.github.com/users/dolphin-emu/followers', 'following_url': 'https://api.github.com/users/dolphin-emu/following{/other_user}', 'gists_url': 'https://api.github.com/users/dolphin-emu/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/dolphin-emu/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/dolphin-emu/subscriptions', 'organizations_url': 'https://api.github.com/users/dolphin-emu/orgs', 'repos_url': 'https://api.github.com/users/dolphin-emu/repos', 'events_url': 'https://api.github.com/users/dolphin-emu/events{/privacy}', 'received_events_url': 'https://api.github.com/users/dolphin-emu/received_events', 'type': 'Organization', 'user_view_type': 'public', 'site_admin': False}, 'html_url': 'https://github.com/dolphin-emu/dolphin', 'description': 'Dolphin is a GameCube / Wii emulator, allowing you to play games for these two platforms on PC with improvements.', 'fork': False, 'url': 'https://api.github.com/repos/dolphin-emu/dolphin', 'forks_url': 'https://api.github.com/repos/dolphin-emu/dolphin/forks', 'keys_url': 'https://api.github.com/repos/dolphin-emu/dolphin/keys{/key_id}', 'collaborators_url': 'https://api.github.com/repos/dolphin-emu/dolphin/collaborators{/collaborator}', 'teams_url': 'https://api.github.com/repos/dolphin-emu/dolphin/teams', 'hooks_url': 'https://api.github.com/repos/dolphin-emu/dolphin/hooks', 'issue_events_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/events{/number}', 'events_url': 'https://api.github.com/repos/dolphin-emu/dolphin/events', 'assignees_url': 'https://api.github.com/repos/dolphin-emu/dolphin/assignees{/user}', 'branches_url': 'https://api.github.com/repos/dolphin-emu/dolphin/branches{/branch}', 'tags_url': 'https://api.github.com/repos/dolphin-emu/dolphin/tags', 'blobs_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/blobs{/sha}', 'git_tags_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/tags{/sha}', 'git_refs_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/refs{/sha}', 'trees_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/trees{/sha}', 'statuses_url': 'https://api.github.com/repos/dolphin-emu/dolphin/statuses/{sha}', 'languages_url': 'https://api.github.com/repos/dolphin-emu/dolphin/languages', 'stargazers_url': 'https://api.github.com/repos/dolphin-emu/dolphin/stargazers', 'contributors_url': 'https://api.github.com/repos/dolphin-emu/dolphin/contributors', 'subscribers_url': 'https://api.github.com/repos/dolphin-emu/dolphin/subscribers', 'subscription_url': 'https://api.github.com/repos/dolphin-emu/dolphin/subscription', 'commits_url': 'https://api.github.com/repos/dolphin-emu/dolphin/commits{/sha}', 'git_commits_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/commits{/sha}', 'comments_url': 'https://api.github.com/repos/dolphin-emu/dolphin/comments{/number}', 'issue_comment_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/comments{/number}', 'contents_url': 'https://api.github.com/repos/dolphin-emu/dolphin/contents/{+path}', 'compare_url': 'https://api.github.com/repos/dolphin-emu/dolphin/compare/{base}...{head}', 'merges_url': 'https://api.github.com/repos/dolphin-emu/dolphin/merges', 'archive_url': 'https://api.github.com/repos/dolphin-emu/dolphin/{archive_format}{/ref}', 'downloads_url': 'https://api.github.com/repos/dolphin-emu/dolphin/downloads', 'issues_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues{/number}', 'pulls_url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls{/number}', 'milestones_url': 'https://api.github.com/repos/dolphin-emu/dolphin/milestones{/number}', 'notifications_url': 'https://api.github.com/repos/dolphin-emu/dolphin/notifications{?since,all,participating}', 'labels_url': 'https://api.github.com/repos/dolphin-emu/dolphin/labels{/name}', 'releases_url': 'https://api.github.com/repos/dolphin-emu/dolphin/releases{/id}', 'deployments_url': 'https://api.github.com/repos/dolphin-emu/dolphin/deployments', 'created_at': '2013-07-22T09:07:57Z', 'updated_at': '2026-07-18T23:13:54Z', 'pushed_at': '2026-07-18T10:34:54Z', 'git_url': 'git://github.com/dolphin-emu/dolphin.git', 'ssh_url': 'git@github.com:dolphin-emu/dolphin.git', 'clone_url': 'https://github.com/dolphin-emu/dolphin.git', 'svn_url': 'https://github.com/dolphin-emu/dolphin', 'homepage': 'https://dolphin-emu.org', 'size': 558448, 'stargazers_count': 15273, 'watchers_count': 15273, 'language': 'C++', 'has_issues': False, 'has_projects': False, 'has_downloads': True, 'has_wiki': True, 'has_pages': False, 'has_discussions': False, 'forks_count': 3162, 'mirror_url': None, 'archived': False, 'disabled': False, 'open_issues_count': 446, 'license': {'key': 'other', 'name': 'Other', 'spdx_id': 'NOASSERTION', 'url': None, 'node_id': 'MDc6TGljZW5zZTA='}, 'allow_forking': True, 'is_template': False, 'web_commit_signoff_required': False, 'has_pull_requests': True, 'pull_request_creation_policy': 'all', 'topics': ['cpp', 'emulation', 'emulator', 'gamecube', 'wii'], 'visibility': 'public', 'forks': 3162, 'open_issues': 446, 'watchers': 15273, 'default_branch': 'master', 'allow_squash_merge': False, 'allow_merge_commit': True, 'allow_rebase_merge': False, 'allow_auto_merge': False, 'delete_branch_on_merge': False, 'allow_update_branch': False, 'use_squash_pr_title_as_default': False, 'squash_merge_commit_message': 'COMMIT_MESSAGES', 'squash_merge_commit_title': 'COMMIT_OR_PR_TITLE', 'merge_commit_message': 'PR_TITLE', 'merge_commit_title': 'MERGE_MESSAGE'}}, '_links': {'self': {'href': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/14731'}, 'html': {'href': 'https://github.com/dolphin-emu/dolphin/pull/14731'}, 'issue': {'href': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/14731'}, 'comments': {'href': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/14731/comments'}, 'review_comments': {'href': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/14731/comments'}, 'review_comment': {'href': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/comments{/number}'}, 'commits': {'href': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/14731/commits'}, 'statuses': {'href': 'https://api.github.com/repos/dolphin-emu/dolphin/statuses/24b41d58df2315831b74f76b95417f2739d02f9d'}}, 'author_association': 'NONE', 'auto_merge': None, 'assignee': None, 'active_lock_reason': None}, 'repository': {'id': 11577304, 'node_id': 'MDEwOlJlcG9zaXRvcnkxMTU3NzMwNA==', 'name': 'dolphin', 'full_name': 'dolphin-emu/dolphin', 'private': False, 'owner': {'login': 'dolphin-emu', 'id': 5050316, 'node_id': 'MDEyOk9yZ2FuaXphdGlvbjUwNTAzMTY=', 'avatar_url': 'https://avatars.githubusercontent.com/u/5050316?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/dolphin-emu', 'html_url': 'https://github.com/dolphin-emu', 'followers_url': 'https://api.github.com/users/dolphin-emu/followers', 'following_url': 'https://api.github.com/users/dolphin-emu/following{/other_user}', 'gists_url': 'https://api.github.com/users/dolphin-emu/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/dolphin-emu/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/dolphin-emu/subscriptions', 'organizations_url': 'https://api.github.com/users/dolphin-emu/orgs', 'repos_url': 'https://api.github.com/users/dolphin-emu/repos', 'events_url': 'https://api.github.com/users/dolphin-emu/events{/privacy}', 'received_events_url': 'https://api.github.com/users/dolphin-emu/received_events', 'type': 'Organization', 'user_view_type': 'public', 'site_admin': False}, 'html_url': 'https://github.com/dolphin-emu/dolphin', 'description': 'Dolphin is a GameCube / Wii emulator, allowing you to play games for these two platforms on PC with improvements.', 'fork': False, 'url': 'https://api.github.com/repos/dolphin-emu/dolphin', 'forks_url': 'https://api.github.com/repos/dolphin-emu/dolphin/forks', 'keys_url': 'https://api.github.com/repos/dolphin-emu/dolphin/keys{/key_id}', 'collaborators_url': 'https://api.github.com/repos/dolphin-emu/dolphin/collaborators{/collaborator}', 'teams_url': 'https://api.github.com/repos/dolphin-emu/dolphin/teams', 'hooks_url': 'https://api.github.com/repos/dolphin-emu/dolphin/hooks', 'issue_events_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/events{/number}', 'events_url': 'https://api.github.com/repos/dolphin-emu/dolphin/events', 'assignees_url': 'https://api.github.com/repos/dolphin-emu/dolphin/assignees{/user}', 'branches_url': 'https://api.github.com/repos/dolphin-emu/dolphin/branches{/branch}', 'tags_url': 'https://api.github.com/repos/dolphin-emu/dolphin/tags', 'blobs_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/blobs{/sha}', 'git_tags_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/tags{/sha}', 'git_refs_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/refs{/sha}', 'trees_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/trees{/sha}', 'statuses_url': 'https://api.github.com/repos/dolphin-emu/dolphin/statuses/{sha}', 'languages_url': 'https://api.github.com/repos/dolphin-emu/dolphin/languages', 'stargazers_url': 'https://api.github.com/repos/dolphin-emu/dolphin/stargazers', 'contributors_url': 'https://api.github.com/repos/dolphin-emu/dolphin/contributors', 'subscribers_url': 'https://api.github.com/repos/dolphin-emu/dolphin/subscribers', 'subscription_url': 'https://api.github.com/repos/dolphin-emu/dolphin/subscription', 'commits_url': 'https://api.github.com/repos/dolphin-emu/dolphin/commits{/sha}', 'git_commits_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/commits{/sha}', 'comments_url': 'https://api.github.com/repos/dolphin-emu/dolphin/comments{/number}', 'issue_comment_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/comments{/number}', 'contents_url': 'https://api.github.com/repos/dolphin-emu/dolphin/contents/{+path}', 'compare_url': 'https://api.github.com/repos/dolphin-emu/dolphin/compare/{base}...{head}', 'merges_url': 'https://api.github.com/repos/dolphin-emu/dolphin/merges', 'archive_url': 'https://api.github.com/repos/dolphin-emu/dolphin/{archive_format}{/ref}', 'downloads_url': 'https://api.github.com/repos/dolphin-emu/dolphin/downloads', 'issues_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues{/number}', 'pulls_url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls{/number}', 'milestones_url': 'https://api.github.com/repos/dolphin-emu/dolphin/milestones{/number}', 'notifications_url': 'https://api.github.com/repos/dolphin-emu/dolphin/notifications{?since,all,participating}', 'labels_url': 'https://api.github.com/repos/dolphin-emu/dolphin/labels{/name}', 'releases_url': 'https://api.github.com/repos/dolphin-emu/dolphin/releases{/id}', 'deployments_url': 'https://api.github.com/repos/dolphin-emu/dolphin/deployments', 'created_at': '2013-07-22T09:07:57Z', 'updated_at': '2026-07-18T23:13:54Z', 'pushed_at': '2026-07-18T10:34:54Z', 'git_url': 'git://github.com/dolphin-emu/dolphin.git', 'ssh_url': 'git@github.com:dolphin-emu/dolphin.git', 'clone_url': 'https://github.com/dolphin-emu/dolphin.git', 'svn_url': 'https://github.com/dolphin-emu/dolphin', 'homepage': 'https://dolphin-emu.org', 'size': 558448, 'stargazers_count': 15273, 'watchers_count': 15273, 'language': 'C++', 'has_issues': False, 'has_projects': False, 'has_downloads': True, 'has_wiki': True, 'has_pages': False, 'has_discussions': False, 'forks_count': 3162, 'mirror_url': None, 'archived': False, 'disabled': False, 'open_issues_count': 446, 'license': {'key': 'other', 'name': 'Other', 'spdx_id': 'NOASSERTION', 'url': None, 'node_id': 'MDc6TGljZW5zZTA='}, 'allow_forking': True, 'is_template': False, 'web_commit_signoff_required': False, 'has_pull_requests': True, 'pull_request_creation_policy': 'all', 'topics': ['cpp', 'emulation', 'emulator', 'gamecube', 'wii'], 'visibility': 'public', 'forks': 3162, 'open_issues': 446, 'watchers': 15273, 'default_branch': 'master', 'custom_properties': {}}, 'organization': {'login': 'dolphin-emu', 'id': 5050316, 'node_id': 'MDEyOk9yZ2FuaXphdGlvbjUwNTAzMTY=', 'url': 'https://api.github.com/orgs/dolphin-emu', 'repos_url': 'https://api.github.com/orgs/dolphin-emu/repos', 'events_url': 'https://api.github.com/orgs/dolphin-emu/events', 'hooks_url': 'https://api.github.com/orgs/dolphin-emu/hooks', 'issues_url': 'https://api.github.com/orgs/dolphin-emu/issues', 'members_url': 'https://api.github.com/orgs/dolphin-emu/members{/member}', 'public_members_url': 'https://api.github.com/orgs/dolphin-emu/public_members{/member}', 'avatar_url': 'https://avatars.githubusercontent.com/u/5050316?v=4', 'description': ''}, 'sender': {'login': 'phire', 'id': 138484, 'node_id': 'MDQ6VXNlcjEzODQ4NA==', 'avatar_url': 'https://avatars.githubusercontent.com/u/138484?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/phire', 'html_url': 'https://github.com/phire', 'followers_url': 'https://api.github.com/users/phire/followers', 'following_url': 'https://api.github.com/users/phire/following{/other_user}', 'gists_url': 'https://api.github.com/users/phire/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/phire/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/phire/subscriptions', 'organizations_url': 'https://api.github.com/users/phire/orgs', 'repos_url': 'https://api.github.com/users/phire/repos', 'events_url': 'https://api.github.com/users/phire/events{/privacy}', 'received_events_url': 'https://api.github.com/users/phire/received_events', 'type': 'User', 'user_view_type': 'public', 'site_admin': False}, 'installation': {'id': 35437981, 'node_id': 'MDIzOkludGVncmF0aW9uSW5zdGFsbGF0aW9uMzU0Mzc5ODE='}}, 'type': 'raw_gh_hook'}
2026-07-18T23:41:29.024924	{'source': 'ghhookparser', 'repo': 'dolphin-emu/dolphin', 'author': 'phire', 'action': 'created', 'id': 14731, 'hash': '24b41d58df2315831b74f76b95417f2739d02f9d', 'url': 'https://github.com/dolphin-emu/dolphin/pull/14731#discussion_r3609425504', 'is_part_of_review': False, 'type': 'gh_pull_request_comment'}
2026-07-18T23:41:29.022761	{'source': 'webserver', 'gh_type': 'pull_request_review', 'raw': {'action': 'submitted', 'review': {'id': 4729506940, 'node_id': 'PRR_kwDOALCn2M8AAAABGeaMfA', 'user': {'login': 'phire', 'id': 138484, 'node_id': 'MDQ6VXNlcjEzODQ4NA==', 'avatar_url': 'https://avatars.githubusercontent.com/u/138484?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/phire', 'html_url': 'https://github.com/phire', 'followers_url': 'https://api.github.com/users/phire/followers', 'following_url': 'https://api.github.com/users/phire/following{/other_user}', 'gists_url': 'https://api.github.com/users/phire/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/phire/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/phire/subscriptions', 'organizations_url': 'https://api.github.com/users/phire/orgs', 'repos_url': 'https://api.github.com/users/phire/repos', 'events_url': 'https://api.github.com/users/phire/events{/privacy}', 'received_events_url': 'https://api.github.com/users/phire/received_events', 'type': 'User', 'user_view_type': 'public', 'site_admin': False}, 'body': None, 'commit_id': '24b41d58df2315831b74f76b95417f2739d02f9d', 'state': 'commented', 'html_url': 'https://github.com/dolphin-emu/dolphin/pull/14731#pullrequestreview-4729506940', 'pull_request_url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/14731', '_links': {'html': {'href': 'https://github.com/dolphin-emu/dolphin/pull/14731#pullrequestreview-4729506940'}, 'pull_request': {'href': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/14731'}}, 'submitted_at': '2026-07-18T23:41:27Z', 'updated_at': '2026-07-18T23:41:27Z', 'author_association': 'MEMBER'}, 'pull_request': {'url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/14731', 'id': 4056977334, 'node_id': 'PR_kwDOALCn2M7x0I-2', 'html_url': 'https://github.com/dolphin-emu/dolphin/pull/14731', 'diff_url': 'https://github.com/dolphin-emu/dolphin/pull/14731.diff', 'patch_url': 'https://github.com/dolphin-emu/dolphin/pull/14731.patch', 'issue_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/14731', 'number': 14731, 'state': 'open', 'locked': False, 'title': 'Convert To WBFS Support', 'user': {'login': 'thethiny', 'id': 6018214, 'node_id': 'MDQ6VXNlcjYwMTgyMTQ=', 'avatar_url': 'https://avatars.githubusercontent.com/u/6018214?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/thethiny', 'html_url': 'https://github.com/thethiny', 'followers_url': 'https://api.github.com/users/thethiny/followers', 'following_url': 'https://api.github.com/users/thethiny/following{/other_user}', 'gists_url': 'https://api.github.com/users/thethiny/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/thethiny/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/thethiny/subscriptions', 'organizations_url': 'https://api.github.com/users/thethiny/orgs', 'repos_url': 'https://api.github.com/users/thethiny/repos', 'events_url': 'https://api.github.com/users/thethiny/events{/privacy}', 'received_events_url': 'https://api.github.com/users/thethiny/received_events', 'type': 'User', 'user_view_type': 'public', 'site_admin': False}, 'body': "This PR introduces Conversion **to** WBFS support. WBFS is the format that is used by USB Loaders on a real Wii device.\r\n\r\n## Design decisions & hardcoded values\r\nThe writer uses fixed sector sizes that match what [libwbfs (the reference implementation by kwiirk)](https://github.com/kwiirk/wbfs/blob/master/libwbfs/libwbfs.c#L128-L134) computes for a standard single-layer Wii disc. These 2 hardcodes are stable and work correctly across all my testings.\r\n- HD sector shift: 9 (512 bytes)\r\n- WBFS sector shift: 21 (2 MiB)\r\nThese are not configurable via the UI. All existing WBFS tools use these values, and since the aim is to support USB Loaders then this has been tested and it is working on a real Wii.\r\n\r\nConverting from WBFS is not enabled. The existing `WbfsFileReader` reports `DataSizeType::UpperBound`, and `ShouldAllowConversion()` requires `Accurate`. I am able to support this but since it was hardcoded by the Dolphin team I thought a discussion is warranted.\r\n\r\n## Testing\r\n- Verified with DolphinTool header and DolphinTool verify\r\n- Verified with wit FILETYPE and wit DUMP (Wiimm's ISO Tools recognizes valid WBFS structure, partitions, encryption)\r\n- Tested ISO to WBFS and RVZ to WBFS conversions\r\n- Output file sizes match Wii Backup Manager when scrubbing is enabled (~0.1% difference), works when scrubbing is disabled.\r\n- Output WBFS files play correctly in Dolphin\r\n- Output WBFS files play correctly on a real Wii using USB Loader GX e25c4f3\r\n", 'created_at': '2026-07-15T01:16:25Z', 'updated_at': '2026-07-18T23:37:35Z', 'closed_at': None, 'merged_at': None, 'merge_commit_sha': '228f93416dd80eb09da834ad7852c8eaa4d9212b', 'assignees': [], 'requested_reviewers': [], 'requested_teams': [], 'labels': [], 'milestone': None, 'draft': False, 'commits_url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/14731/commits', 'review_comments_url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/14731/comments', 'review_comment_url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/comments{/number}', 'comments_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/14731/comments', 'statuses_url': 'https://api.github.com/repos/dolphin-emu/dolphin/statuses/24b41d58df2315831b74f76b95417f2739d02f9d', 'head': {'label': 'thethiny:wbfs-conversion', 'ref': 'wbfs-conversion', 'sha': '24b41d58df2315831b74f76b95417f2739d02f9d', 'user': {'login': 'thethiny', 'id': 6018214, 'node_id': 'MDQ6VXNlcjYwMTgyMTQ=', 'avatar_url': 'https://avatars.githubusercontent.com/u/6018214?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/thethiny', 'html_url': 'https://github.com/thethiny', 'followers_url': 'https://api.github.com/users/thethiny/followers', 'following_url': 'https://api.github.com/users/thethiny/following{/other_user}', 'gists_url': 'https://api.github.com/users/thethiny/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/thethiny/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/thethiny/subscriptions', 'organizations_url': 'https://api.github.com/users/thethiny/orgs', 'repos_url': 'https://api.github.com/users/thethiny/repos', 'events_url': 'https://api.github.com/users/thethiny/events{/privacy}', 'received_events_url': 'https://api.github.com/users/thethiny/received_events', 'type': 'User', 'user_view_type': 'public', 'site_admin': False}, 'repo': {'id': 1298654395, 'node_id': 'R_kgDOTWfkuw', 'name': 'dolphin', 'full_name': 'thethiny/dolphin', 'private': False, 'owner': {'login': 'thethiny', 'id': 6018214, 'node_id': 'MDQ6VXNlcjYwMTgyMTQ=', 'avatar_url': 'https://avatars.githubusercontent.com/u/6018214?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/thethiny', 'html_url': 'https://github.com/thethiny', 'followers_url': 'https://api.github.com/users/thethiny/followers', 'following_url': 'https://api.github.com/users/thethiny/following{/other_user}', 'gists_url': 'https://api.github.com/users/thethiny/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/thethiny/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/thethiny/subscriptions', 'organizations_url': 'https://api.github.com/users/thethiny/orgs', 'repos_url': 'https://api.github.com/users/thethiny/repos', 'events_url': 'https://api.github.com/users/thethiny/events{/privacy}', 'received_events_url': 'https://api.github.com/users/thethiny/received_events', 'type': 'User', 'user_view_type': 'public', 'site_admin': False}, 'html_url': 'https://github.com/thethiny/dolphin', 'description': 'Dolphin is a GameCube / Wii emulator, allowing you to play games for these two platforms on PC with improvements.', 'fork': True, 'url': 'https://api.github.com/repos/thethiny/dolphin', 'forks_url': 'https://api.github.com/repos/thethiny/dolphin/forks', 'keys_url': 'https://api.github.com/repos/thethiny/dolphin/keys{/key_id}', 'collaborators_url': 'https://api.github.com/repos/thethiny/dolphin/collaborators{/collaborator}', 'teams_url': 'https://api.github.com/repos/thethiny/dolphin/teams', 'hooks_url': 'https://api.github.com/repos/thethiny/dolphin/hooks', 'issue_events_url': 'https://api.github.com/repos/thethiny/dolphin/issues/events{/number}', 'events_url': 'https://api.github.com/repos/thethiny/dolphin/events', 'assignees_url': 'https://api.github.com/repos/thethiny/dolphin/assignees{/user}', 'branches_url': 'https://api.github.com/repos/thethiny/dolphin/branches{/branch}', 'tags_url': 'https://api.github.com/repos/thethiny/dolphin/tags', 'blobs_url': 'https://api.github.com/repos/thethiny/dolphin/git/blobs{/sha}', 'git_tags_url': 'https://api.github.com/repos/thethiny/dolphin/git/tags{/sha}', 'git_refs_url': 'https://api.github.com/repos/thethiny/dolphin/git/refs{/sha}', 'trees_url': 'https://api.github.com/repos/thethiny/dolphin/git/trees{/sha}', 'statuses_url': 'https://api.github.com/repos/thethiny/dolphin/statuses/{sha}', 'languages_url': 'https://api.github.com/repos/thethiny/dolphin/languages', 'stargazers_url': 'https://api.github.com/repos/thethiny/dolphin/stargazers', 'contributors_url': 'https://api.github.com/repos/thethiny/dolphin/contributors', 'subscribers_url': 'https://api.github.com/repos/thethiny/dolphin/subscribers', 'subscription_url': 'https://api.github.com/repos/thethiny/dolphin/subscription', 'commits_url': 'https://api.github.com/repos/thethiny/dolphin/commits{/sha}', 'git_commits_url': 'https://api.github.com/repos/thethiny/dolphin/git/commits{/sha}', 'comments_url': 'https://api.github.com/repos/thethiny/dolphin/comments{/number}', 'issue_comment_url': 'https://api.github.com/repos/thethiny/dolphin/issues/comments{/number}', 'contents_url': 'https://api.github.com/repos/thethiny/dolphin/contents/{+path}', 'compare_url': 'https://api.github.com/repos/thethiny/dolphin/compare/{base}...{head}', 'merges_url': 'https://api.github.com/repos/thethiny/dolphin/merges', 'archive_url': 'https://api.github.com/repos/thethiny/dolphin/{archive_format}{/ref}', 'downloads_url': 'https://api.github.com/repos/thethiny/dolphin/downloads', 'issues_url': 'https://api.github.com/repos/thethiny/dolphin/issues{/number}', 'pulls_url': 'https://api.github.com/repos/thethiny/dolphin/pulls{/number}', 'milestones_url': 'https://api.github.com/repos/thethiny/dolphin/milestones{/number}', 'notifications_url': 'https://api.github.com/repos/thethiny/dolphin/notifications{?since,all,participating}', 'labels_url': 'https://api.github.com/repos/thethiny/dolphin/labels{/name}', 'releases_url': 'https://api.github.com/repos/thethiny/dolphin/releases{/id}', 'deployments_url': 'https://api.github.com/repos/thethiny/dolphin/deployments', 'created_at': '2026-07-12T22:09:13Z', 'updated_at': '2026-07-12T22:09:13Z', 'pushed_at': '2026-07-18T20:35:03Z', 'git_url': 'git://github.com/thethiny/dolphin.git', 'ssh_url': 'git@github.com:thethiny/dolphin.git', 'clone_url': 'https://github.com/thethiny/dolphin.git', 'svn_url': 'https://github.com/thethiny/dolphin', 'homepage': 'https://dolphin-emu.org', 'size': 515471, 'stargazers_count': 0, 'watchers_count': 0, 'language': None, 'has_issues': False, 'has_projects': True, 'has_downloads': True, 'has_wiki': True, 'has_pages': False, 'has_discussions': False, 'forks_count': 0, 'mirror_url': None, 'archived': False, 'disabled': False, 'open_issues_count': 0, 'license': {'key': 'other', 'name': 'Other', 'spdx_id': 'NOASSERTION', 'url': None, 'node_id': 'MDc6TGljZW5zZTA='}, 'allow_forking': True, 'is_template': False, 'web_commit_signoff_required': False, 'has_pull_requests': True, 'pull_request_creation_policy': 'all', 'topics': [], 'visibility': 'public', 'forks': 0, 'open_issues': 0, 'watchers': 0, 'default_branch': 'master', 'allow_squash_merge': True, 'allow_merge_commit': True, 'allow_rebase_merge': True, 'allow_auto_merge': False, 'delete_branch_on_merge': False, 'allow_update_branch': False, 'use_squash_pr_title_as_default': False, 'squash_merge_commit_message': 'COMMIT_MESSAGES', 'squash_merge_commit_title': 'COMMIT_OR_PR_TITLE', 'merge_commit_message': 'PR_TITLE', 'merge_commit_title': 'MERGE_MESSAGE'}}, 'base': {'label': 'dolphin-emu:master', 'ref': 'master', 'sha': 'd3b2943807dd0073f7767947466dd73cccfef319', 'user': {'login': 'dolphin-emu', 'id': 5050316, 'node_id': 'MDEyOk9yZ2FuaXphdGlvbjUwNTAzMTY=', 'avatar_url': 'https://avatars.githubusercontent.com/u/5050316?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/dolphin-emu', 'html_url': 'https://github.com/dolphin-emu', 'followers_url': 'https://api.github.com/users/dolphin-emu/followers', 'following_url': 'https://api.github.com/users/dolphin-emu/following{/other_user}', 'gists_url': 'https://api.github.com/users/dolphin-emu/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/dolphin-emu/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/dolphin-emu/subscriptions', 'organizations_url': 'https://api.github.com/users/dolphin-emu/orgs', 'repos_url': 'https://api.github.com/users/dolphin-emu/repos', 'events_url': 'https://api.github.com/users/dolphin-emu/events{/privacy}', 'received_events_url': 'https://api.github.com/users/dolphin-emu/received_events', 'type': 'Organization', 'user_view_type': 'public', 'site_admin': False}, 'repo': {'id': 11577304, 'node_id': 'MDEwOlJlcG9zaXRvcnkxMTU3NzMwNA==', 'name': 'dolphin', 'full_name': 'dolphin-emu/dolphin', 'private': False, 'owner': {'login': 'dolphin-emu', 'id': 5050316, 'node_id': 'MDEyOk9yZ2FuaXphdGlvbjUwNTAzMTY=', 'avatar_url': 'https://avatars.githubusercontent.com/u/5050316?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/dolphin-emu', 'html_url': 'https://github.com/dolphin-emu', 'followers_url': 'https://api.github.com/users/dolphin-emu/followers', 'following_url': 'https://api.github.com/users/dolphin-emu/following{/other_user}', 'gists_url': 'https://api.github.com/users/dolphin-emu/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/dolphin-emu/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/dolphin-emu/subscriptions', 'organizations_url': 'https://api.github.com/users/dolphin-emu/orgs', 'repos_url': 'https://api.github.com/users/dolphin-emu/repos', 'events_url': 'https://api.github.com/users/dolphin-emu/events{/privacy}', 'received_events_url': 'https://api.github.com/users/dolphin-emu/received_events', 'type': 'Organization', 'user_view_type': 'public', 'site_admin': False}, 'html_url': 'https://github.com/dolphin-emu/dolphin', 'description': 'Dolphin is a GameCube / Wii emulator, allowing you to play games for these two platforms on PC with improvements.', 'fork': False, 'url': 'https://api.github.com/repos/dolphin-emu/dolphin', 'forks_url': 'https://api.github.com/repos/dolphin-emu/dolphin/forks', 'keys_url': 'https://api.github.com/repos/dolphin-emu/dolphin/keys{/key_id}', 'collaborators_url': 'https://api.github.com/repos/dolphin-emu/dolphin/collaborators{/collaborator}', 'teams_url': 'https://api.github.com/repos/dolphin-emu/dolphin/teams', 'hooks_url': 'https://api.github.com/repos/dolphin-emu/dolphin/hooks', 'issue_events_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/events{/number}', 'events_url': 'https://api.github.com/repos/dolphin-emu/dolphin/events', 'assignees_url': 'https://api.github.com/repos/dolphin-emu/dolphin/assignees{/user}', 'branches_url': 'https://api.github.com/repos/dolphin-emu/dolphin/branches{/branch}', 'tags_url': 'https://api.github.com/repos/dolphin-emu/dolphin/tags', 'blobs_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/blobs{/sha}', 'git_tags_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/tags{/sha}', 'git_refs_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/refs{/sha}', 'trees_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/trees{/sha}', 'statuses_url': 'https://api.github.com/repos/dolphin-emu/dolphin/statuses/{sha}', 'languages_url': 'https://api.github.com/repos/dolphin-emu/dolphin/languages', 'stargazers_url': 'https://api.github.com/repos/dolphin-emu/dolphin/stargazers', 'contributors_url': 'https://api.github.com/repos/dolphin-emu/dolphin/contributors', 'subscribers_url': 'https://api.github.com/repos/dolphin-emu/dolphin/subscribers', 'subscription_url': 'https://api.github.com/repos/dolphin-emu/dolphin/subscription', 'commits_url': 'https://api.github.com/repos/dolphin-emu/dolphin/commits{/sha}', 'git_commits_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/commits{/sha}', 'comments_url': 'https://api.github.com/repos/dolphin-emu/dolphin/comments{/number}', 'issue_comment_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/comments{/number}', 'contents_url': 'https://api.github.com/repos/dolphin-emu/dolphin/contents/{+path}', 'compare_url': 'https://api.github.com/repos/dolphin-emu/dolphin/compare/{base}...{head}', 'merges_url': 'https://api.github.com/repos/dolphin-emu/dolphin/merges', 'archive_url': 'https://api.github.com/repos/dolphin-emu/dolphin/{archive_format}{/ref}', 'downloads_url': 'https://api.github.com/repos/dolphin-emu/dolphin/downloads', 'issues_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues{/number}', 'pulls_url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls{/number}', 'milestones_url': 'https://api.github.com/repos/dolphin-emu/dolphin/milestones{/number}', 'notifications_url': 'https://api.github.com/repos/dolphin-emu/dolphin/notifications{?since,all,participating}', 'labels_url': 'https://api.github.com/repos/dolphin-emu/dolphin/labels{/name}', 'releases_url': 'https://api.github.com/repos/dolphin-emu/dolphin/releases{/id}', 'deployments_url': 'https://api.github.com/repos/dolphin-emu/dolphin/deployments', 'created_at': '2013-07-22T09:07:57Z', 'updated_at': '2026-07-18T23:13:54Z', 'pushed_at': '2026-07-18T10:34:54Z', 'git_url': 'git://github.com/dolphin-emu/dolphin.git', 'ssh_url': 'git@github.com:dolphin-emu/dolphin.git', 'clone_url': 'https://github.com/dolphin-emu/dolphin.git', 'svn_url': 'https://github.com/dolphin-emu/dolphin', 'homepage': 'https://dolphin-emu.org', 'size': 558448, 'stargazers_count': 15273, 'watchers_count': 15273, 'language': 'C++', 'has_issues': False, 'has_projects': False, 'has_downloads': True, 'has_wiki': True, 'has_pages': False, 'has_discussions': False, 'forks_count': 3162, 'mirror_url': None, 'archived': False, 'disabled': False, 'open_issues_count': 446, 'license': {'key': 'other', 'name': 'Other', 'spdx_id': 'NOASSERTION', 'url': None, 'node_id': 'MDc6TGljZW5zZTA='}, 'allow_forking': True, 'is_template': False, 'web_commit_signoff_required': False, 'has_pull_requests': True, 'pull_request_creation_policy': 'all', 'topics': ['cpp', 'emulation', 'emulator', 'gamecube', 'wii'], 'visibility': 'public', 'forks': 3162, 'open_issues': 446, 'watchers': 15273, 'default_branch': 'master', 'allow_squash_merge': False, 'allow_merge_commit': True, 'allow_rebase_merge': False, 'allow_auto_merge': False, 'delete_branch_on_merge': False, 'allow_update_branch': False, 'use_squash_pr_title_as_default': False, 'squash_merge_commit_message': 'COMMIT_MESSAGES', 'squash_merge_commit_title': 'COMMIT_OR_PR_TITLE', 'merge_commit_message': 'PR_TITLE', 'merge_commit_title': 'MERGE_MESSAGE'}}, '_links': {'self': {'href': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/14731'}, 'html': {'href': 'https://github.com/dolphin-emu/dolphin/pull/14731'}, 'issue': {'href': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/14731'}, 'comments': {'href': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/14731/comments'}, 'review_comments': {'href': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/14731/comments'}, 'review_comment': {'href': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/comments{/number}'}, 'commits': {'href': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/14731/commits'}, 'statuses': {'href': 'https://api.github.com/repos/dolphin-emu/dolphin/statuses/24b41d58df2315831b74f76b95417f2739d02f9d'}}, 'author_association': 'NONE', 'auto_merge': None, 'assignee': None, 'active_lock_reason': None}, 'repository': {'id': 11577304, 'node_id': 'MDEwOlJlcG9zaXRvcnkxMTU3NzMwNA==', 'name': 'dolphin', 'full_name': 'dolphin-emu/dolphin', 'private': False, 'owner': {'login': 'dolphin-emu', 'id': 5050316, 'node_id': 'MDEyOk9yZ2FuaXphdGlvbjUwNTAzMTY=', 'avatar_url': 'https://avatars.githubusercontent.com/u/5050316?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/dolphin-emu', 'html_url': 'https://github.com/dolphin-emu', 'followers_url': 'https://api.github.com/users/dolphin-emu/followers', 'following_url': 'https://api.github.com/users/dolphin-emu/following{/other_user}', 'gists_url': 'https://api.github.com/users/dolphin-emu/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/dolphin-emu/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/dolphin-emu/subscriptions', 'organizations_url': 'https://api.github.com/users/dolphin-emu/orgs', 'repos_url': 'https://api.github.com/users/dolphin-emu/repos', 'events_url': 'https://api.github.com/users/dolphin-emu/events{/privacy}', 'received_events_url': 'https://api.github.com/users/dolphin-emu/received_events', 'type': 'Organization', 'user_view_type': 'public', 'site_admin': False}, 'html_url': 'https://github.com/dolphin-emu/dolphin', 'description': 'Dolphin is a GameCube / Wii emulator, allowing you to play games for these two platforms on PC with improvements.', 'fork': False, 'url': 'https://api.github.com/repos/dolphin-emu/dolphin', 'forks_url': 'https://api.github.com/repos/dolphin-emu/dolphin/forks', 'keys_url': 'https://api.github.com/repos/dolphin-emu/dolphin/keys{/key_id}', 'collaborators_url': 'https://api.github.com/repos/dolphin-emu/dolphin/collaborators{/collaborator}', 'teams_url': 'https://api.github.com/repos/dolphin-emu/dolphin/teams', 'hooks_url': 'https://api.github.com/repos/dolphin-emu/dolphin/hooks', 'issue_events_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/events{/number}', 'events_url': 'https://api.github.com/repos/dolphin-emu/dolphin/events', 'assignees_url': 'https://api.github.com/repos/dolphin-emu/dolphin/assignees{/user}', 'branches_url': 'https://api.github.com/repos/dolphin-emu/dolphin/branches{/branch}', 'tags_url': 'https://api.github.com/repos/dolphin-emu/dolphin/tags', 'blobs_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/blobs{/sha}', 'git_tags_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/tags{/sha}', 'git_refs_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/refs{/sha}', 'trees_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/trees{/sha}', 'statuses_url': 'https://api.github.com/repos/dolphin-emu/dolphin/statuses/{sha}', 'languages_url': 'https://api.github.com/repos/dolphin-emu/dolphin/languages', 'stargazers_url': 'https://api.github.com/repos/dolphin-emu/dolphin/stargazers', 'contributors_url': 'https://api.github.com/repos/dolphin-emu/dolphin/contributors', 'subscribers_url': 'https://api.github.com/repos/dolphin-emu/dolphin/subscribers', 'subscription_url': 'https://api.github.com/repos/dolphin-emu/dolphin/subscription', 'commits_url': 'https://api.github.com/repos/dolphin-emu/dolphin/commits{/sha}', 'git_commits_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/commits{/sha}', 'comments_url': 'https://api.github.com/repos/dolphin-emu/dolphin/comments{/number}', 'issue_comment_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/comments{/number}', 'contents_url': 'https://api.github.com/repos/dolphin-emu/dolphin/contents/{+path}', 'compare_url': 'https://api.github.com/repos/dolphin-emu/dolphin/compare/{base}...{head}', 'merges_url': 'https://api.github.com/repos/dolphin-emu/dolphin/merges', 'archive_url': 'https://api.github.com/repos/dolphin-emu/dolphin/{archive_format}{/ref}', 'downloads_url': 'https://api.github.com/repos/dolphin-emu/dolphin/downloads', 'issues_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues{/number}', 'pulls_url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls{/number}', 'milestones_url': 'https://api.github.com/repos/dolphin-emu/dolphin/milestones{/number}', 'notifications_url': 'https://api.github.com/repos/dolphin-emu/dolphin/notifications{?since,all,participating}', 'labels_url': 'https://api.github.com/repos/dolphin-emu/dolphin/labels{/name}', 'releases_url': 'https://api.github.com/repos/dolphin-emu/dolphin/releases{/id}', 'deployments_url': 'https://api.github.com/repos/dolphin-emu/dolphin/deployments', 'created_at': '2013-07-22T09:07:57Z', 'updated_at': '2026-07-18T23:13:54Z', 'pushed_at': '2026-07-18T10:34:54Z', 'git_url': 'git://github.com/dolphin-emu/dolphin.git', 'ssh_url': 'git@github.com:dolphin-emu/dolphin.git', 'clone_url': 'https://github.com/dolphin-emu/dolphin.git', 'svn_url': 'https://github.com/dolphin-emu/dolphin', 'homepage': 'https://dolphin-emu.org', 'size': 558448, 'stargazers_count': 15273, 'watchers_count': 15273, 'language': 'C++', 'has_issues': False, 'has_projects': False, 'has_downloads': True, 'has_wiki': True, 'has_pages': False, 'has_discussions': False, 'forks_count': 3162, 'mirror_url': None, 'archived': False, 'disabled': False, 'open_issues_count': 446, 'license': {'key': 'other', 'name': 'Other', 'spdx_id': 'NOASSERTION', 'url': None, 'node_id': 'MDc6TGljZW5zZTA='}, 'allow_forking': True, 'is_template': False, 'web_commit_signoff_required': False, 'has_pull_requests': True, 'pull_request_creation_policy': 'all', 'topics': ['cpp', 'emulation', 'emulator', 'gamecube', 'wii'], 'visibility': 'public', 'forks': 3162, 'open_issues': 446, 'watchers': 15273, 'default_branch': 'master', 'custom_properties': {}}, 'organization': {'login': 'dolphin-emu', 'id': 5050316, 'node_id': 'MDEyOk9yZ2FuaXphdGlvbjUwNTAzMTY=', 'url': 'https://api.github.com/orgs/dolphin-emu', 'repos_url': 'https://api.github.com/orgs/dolphin-emu/repos', 'events_url': 'https://api.github.com/orgs/dolphin-emu/events', 'hooks_url': 'https://api.github.com/orgs/dolphin-emu/hooks', 'issues_url': 'https://api.github.com/orgs/dolphin-emu/issues', 'members_url': 'https://api.github.com/orgs/dolphin-emu/members{/member}', 'public_members_url': 'https://api.github.com/orgs/dolphin-emu/public_members{/member}', 'avatar_url': 'https://avatars.githubusercontent.com/u/5050316?v=4', 'description': ''}, 'sender': {'login': 'phire', 'id': 138484, 'node_id': 'MDQ6VXNlcjEzODQ4NA==', 'avatar_url': 'https://avatars.githubusercontent.com/u/138484?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/phire', 'html_url': 'https://github.com/phire', 'followers_url': 'https://api.github.com/users/phire/followers', 'following_url': 'https://api.github.com/users/phire/following{/other_user}', 'gists_url': 'https://api.github.com/users/phire/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/phire/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/phire/subscriptions', 'organizations_url': 'https://api.github.com/users/phire/orgs', 'repos_url': 'https://api.github.com/users/phire/repos', 'events_url': 'https://api.github.com/users/phire/events{/privacy}', 'received_events_url': 'https://api.github.com/users/phire/received_events', 'type': 'User', 'user_view_type': 'public', 'site_admin': False}, 'installation': {'id': 35437981, 'node_id': 'MDIzOkludGVncmF0aW9uSW5zdGFsbGF0aW9uMzU0Mzc5ODE='}}, 'type': 'raw_gh_hook'}
2026-07-18T23:41:29.022743	{'source': 'ghhookparser', 'repo': 'dolphin-emu/dolphin', 'author': 'phire', 'action': 'submitted', 'pr_id': 14731, 'pr_title': 'Convert To WBFS Support', 'state': 'commented', 'url': 'https://github.com/dolphin-emu/dolphin/pull/14731#pullrequestreview-4729506940', 'comments': [{'id': 3609425504, 'node_id': 'PRRC_kwDOALCn2M7XI3Zg', 'url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/comments/3609425504', 'pull_request_review_id': 4729506940, 'diff_hunk': '@@ -186,7 +380,304 @@ std::unique_ptr<WbfsFileReader> WbfsFileReader::Create(File::DirectIOFile file,\n   if (!reader->IsGood())\n     reader.reset();\n \n+  if (reader && reader->m_has_nkit_header)\n+    reader->ReadPartitionInfo();\n+\n   return reader;\n }\n \n+// Converts any disc image to WBFS with an NKit v2 header for lossless round-trips.\n+// Strips disc-level junk and partition-level junk (encrypted sectors whose decrypted\n+// content is zero or LFG padding), records a junk bitmap for reconstruction.\n+// See: https://github.com/dolphin-emu/dolphin/pull/14731\n+bool ConvertToWBFS(BlobReader* infile, const std::string& infile_path,\n+                   const std::string& outfile_path, const CompressCB& callback)\n+{\n+  ASSERT(infile->GetDataSizeType() == DataSizeType::Accurate ||\n+         infile->GetDataSizeType() == DataSizeType::UpperBound);\n+\n+  File::DirectIOFile outfile(outfile_path, File::AccessMode::Write);\n+  if (!outfile.IsOpen())\n+  {\n+    PanicAlertFmtT(\n+        "Failed to open the output file \\"{0}\\".\\n"\n+        "Check that you have permissions to write the target folder and that the media can "\n+        "be written.",\n+        outfile_path);\n+    return false;\n+  }\n+\n+  const u64 disc_size = infile->GetDataSize();\n+\n+  // These match the values used by standard WBFS tools (wwt, WBFS Manager)\n+  static constexpr u8 hd_sector_shift = 9;\n+  static constexpr u8 wbfs_sector_shift = 21;\n+  static constexpr u64 hd_sector_size = 1ull << hd_sector_shift;\n+  static constexpr u64 wbfs_sector_size = 1ull << wbfs_sector_shift;\n+\n+  const u64 blocks_per_disc = (disc_size + wbfs_sector_size - 1) / wbfs_sector_size;\n+  const u64 disc_info_size =\n+      Common::AlignUp(WII_DISC_HEADER_SIZE + blocks_per_disc * sizeof(u16), hd_sector_size);\n+\n+  // Read disc header (first 256 bytes contain disc_id, disc_num, title, etc.)\n+  std::vector<u8> disc_header(WII_DISC_HEADER_SIZE, 0);\n+  if (!infile->Read(0, WII_DISC_HEADER_SIZE, disc_header.data()))\n+  {\n+    PanicAlertFmtT("Failed to read from the input file \\"{0}\\".", infile_path);\n+    return false;\n+  }\n+\n+  // Use Volume for partition info and decrypted reads\n+  struct PartitionInfo\n+  {\n+    u64 data_offset;\n+    u64 data_size;\n+    Partition partition;\n+  };\n+  std::vector<PartitionInfo> partitions;\n+\n+  std::unique_ptr<VolumeDisc> volume = CreateDisc(infile_path);\n+  if (volume)\n+  {\n+    for (const Partition& partition : volume->GetPartitions())\n+    {\n+      const std::optional<u64> data_offset =\n+          volume->ReadSwappedAndShifted(partition.offset + 0x2B8, PARTITION_NONE);\n+      const std::optional<u64> data_size =\n+          volume->ReadSwappedAndShifted(partition.offset + 0x2BC, PARTITION_NONE);\n+      if (!data_offset || !data_size)\n+        continue;\n+\n+      PartitionInfo info;\n+      info.data_offset = partition.offset + *data_offset;\n+      info.data_size = *data_size;\n+      info.partition = partition;\n+      partitions.push_back(info);\n+    }\n+  }\n+\n+  // NKit v2 gap type bitmap: 1 bit per block, MSB-first, always sized for dual-layer\n+  const u64 gap_type_blocks = (DL_DVD_SIZE + wbfs_sector_size - 1) / wbfs_sector_size;\n+  const u64 gap_type_bytes = (gap_type_blocks + 7) / 8;\n+  std::vector<u8> gap_type(gap_type_bytes, 0);\n+\n+  // Compute data_start up front so we can write sectors during the scan\n+  const u64 data_start = Common::AlignUp(hd_sector_size + disc_info_size, wbfs_sector_size);\n+  const u16 wlba_base = static_cast<u16>(data_start / wbfs_sector_size);\n+\n+  // Single pass: scan, classify, hash, and write used sectors in one loop\n+  std::vector<u8> sector_buf(wbfs_sector_size, 0);\n+  std::vector<u16> wlba_table(blocks_per_disc, 0);\n+  u16 used_count = 0;\n+\n+  // NKit v2 stores four hash digests for verification\n+  auto sha1_ctx = Common::SHA1::CreateContext();\n+  u32 crc = Common::StartCRC32();\n+  mbedtls_md5_context md5_ctx{};\n+  mbedtls_md5_init(&md5_ctx);\n+  mbedtls_md5_starts_ret(&md5_ctx);\n+  XXH64_state_t* xxh_state = XXH64_createState();\n+  XXH64_reset(xxh_state, 0);\n+\n+  for (u64 i = 0; i < blocks_per_disc; i++)\n+  {\n+    if (i % 100 == 0)\n+    {\n+      const bool was_cancelled =\n+          !callback(Common::GetStringT("Converting"),\n+                    static_cast<float>(i) / static_cast<float>(blocks_per_disc));\n+      if (was_cancelled)\n+      {\n+        XXH64_freeState(xxh_state);\n+        mbedtls_md5_free(&md5_ctx);\n+        outfile.Close();\n+        File::Delete(outfile_path);\n+        return false;\n+      }\n+    }\n+\n+    const u64 offset = i * wbfs_sector_size;\n+    const size_t sz = static_cast<size_t>(std::min(wbfs_sector_size, disc_size - offset));\n+\n+    if (!infile->Read(offset, sz, sector_buf.data()))', 'path': 'Source/Core/DiscIO/WbfsBlob.cpp', 'position': 409, 'original_position': 409, 'commit_id': '24b41d58df2315831b74f76b95417f2739d02f9d', 'user': {'login': 'phire', 'id': 138484, 'node_id': 'MDQ6VXNlcjEzODQ4NA==', 'avatar_url': 'https://avatars.githubusercontent.com/u/138484?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/phire', 'html_url': 'https://github.com/phire', 'followers_url': 'https://api.github.com/users/phire/followers', 'following_url': 'https://api.github.com/users/phire/following{/other_user}', 'gists_url': 'https://api.github.com/users/phire/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/phire/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/phire/subscriptions', 'organizations_url': 'https://api.github.com/users/phire/orgs', 'repos_url': 'https://api.github.com/users/phire/repos', 'events_url': 'https://api.github.com/users/phire/events{/privacy}', 'received_events_url': 'https://api.github.com/users/phire/received_events', 'type': 'User', 'user_view_type': 'public', 'site_admin': False}, 'body': 'Oh... I forgot about the digests. Guess we do need it. ', 'created_at': '2026-07-18T23:41:27Z', 'updated_at': '2026-07-18T23:41:27Z', 'html_url': 'https://github.com/dolphin-emu/dolphin/pull/14731#discussion_r3609425504', 'pull_request_url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/14731', 'author_association': 'MEMBER', '_links': {'self': {'href': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/comments/3609425504'}, 'html': {'href': 'https://github.com/dolphin-emu/dolphin/pull/14731#discussion_r3609425504'}, 'pull_request': {'href': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/14731'}}, 'original_commit_id': '24b41d58df2315831b74f76b95417f2739d02f9d', 'reactions': {'url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/comments/3609425504/reactions', 'total_count': 0, '+1': 0, '-1': 0, 'laugh': 0, 'hooray': 0, 'confused': 0, 'heart': 0, 'rocket': 0, 'eyes': 0}, 'in_reply_to_id': 3609251889}], 'type': 'gh_pull_request_review'}
2026-07-18T23:40:26.521240	{'source': 'logging', 'level': 'INFO', 'pathname': '/nix/store/m89a38mxx677zd2j3gqq91c40d1i7dc6-central-env/lib/python3.13/site-packages/central/github/authz.py', 'lineno': 30, 'msg': 'New GH %s: %s', 'args': "('dolphin-emu/trusted-developers', 'EmptyChaos,unknownbrackets,CelestialAmber,Ebola16,Geotale,krnlyng,neobrain,CookiePLMonster,degasus,Stevoisiak,LillyJadeKatrin,iwubcode,kamiyo,Filoppi,hthh,rukai,Linkinworm,Parlane,Starsam80,meffij,phire,delroth,vladfi1,zackhow,malleoz,adamdmoss,NanoByte011,randomstuff,lioncash,mrgreywater,cristian64,Ziek,mimimi085181,deReeperJosh,bentley,jezze,orbea,ligfx,tygyh,magumagu,mathieui,skidau,kayru,endrift,jjdelvalle,Tilka,shonumi,Sintendo,Phatcat,TryTwo,marcan,JosJuice,zopieux,Buddybenj,OatmealDome,JoshuaVandaele,Techjar,Simonx22,JMC47,ColinDTaylor,CasualPokePlayer,Lobsterzelda,hrydgard,spxtr,archshift,corwin-mcknight,ShimmerGlass,aroulin,K0bin,LPFaint99,OrN,aldelaro5,skylersaleh,Helios747,CrystalGamma,nickbeth,tom-pratt,spycrab,magcius,RachelBryk,SuperSamus,AdmiralCurtiss,mmastrac,PatrickFerry,gwicks,BhaaLseN,leoetlino,rlnilsen,cscd98,riking,glennricster,Dentomologist,FioraAeterna,jloehr,comex,Linktothepast,galop1n,mandar1jn,RisingFog,moncefmechri,dreamsyntax,jordan-woyak,hdcmeta,MayImilae,Orphis,hackbar,Pokechu22,crediar,Gamer64ytb,booto,linkmauve,Tinob,Zopolis4,nullgemm,Alcaro,smurf3tte,yourWaifu,LAGonauta,sepalani,mitaclaw,JordanTheToaster,noahpistilli,DacoTaco,CrossVR,TellowKrinkle,Hydr8gon,merryhime,mbc07,SirMangler,Sam-Belliveau,mahdihijazi')", 'type': 'internal_log'}
2026-07-18T23:40:25.166133	{'source': 'logging', 'level': 'INFO', 'pathname': '/nix/store/m89a38mxx677zd2j3gqq91c40d1i7dc6-central-env/lib/python3.13/site-packages/central/github/authz.py', 'lineno': 21, 'msg': 'Refreshing list of trusted users (from %s/%s)', 'args': "('dolphin-emu', 'trusted-developers')", 'type': 'internal_log'}
2026-07-18T23:37:37.476476	{'source': 'notifications', 'msg': '[\x1f\x0313dolphin-emu/dolphin\x03\x1f] \x0303t\ufeffhethiny\x03 commented on #14731 24b41d: \x1f\x0302https://dolp.in/pr14731#discussion_r3609419546\x03\x1f', 'type': 'notification'}
2026-07-18T23:37:37.476246	{'source': 'webserver', 'gh_type': 'pull_request_review_comment', 'raw': {'action': 'created', 'comment': {'url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/comments/3609419546', 'pull_request_review_id': 4729501733, 'id': 3609419546, 'node_id': 'PRRC_kwDOALCn2M7XI18a', 'diff_hunk': '@@ -186,7 +380,304 @@ std::unique_ptr<WbfsFileReader> WbfsFileReader::Create(File::DirectIOFile file,\n   if (!reader->IsGood())\n     reader.reset();\n \n+  if (reader && reader->m_has_nkit_header)\n+    reader->ReadPartitionInfo();\n+\n   return reader;\n }\n \n+// Converts any disc image to WBFS with an NKit v2 header for lossless round-trips.\n+// Strips disc-level junk and partition-level junk (encrypted sectors whose decrypted\n+// content is zero or LFG padding), records a junk bitmap for reconstruction.\n+// See: https://github.com/dolphin-emu/dolphin/pull/14731\n+bool ConvertToWBFS(BlobReader* infile, const std::string& infile_path,\n+                   const std::string& outfile_path, const CompressCB& callback)\n+{\n+  ASSERT(infile->GetDataSizeType() == DataSizeType::Accurate ||\n+         infile->GetDataSizeType() == DataSizeType::UpperBound);\n+\n+  File::DirectIOFile outfile(outfile_path, File::AccessMode::Write);\n+  if (!outfile.IsOpen())\n+  {\n+    PanicAlertFmtT(\n+        "Failed to open the output file \\"{0}\\".\\n"\n+        "Check that you have permissions to write the target folder and that the media can "\n+        "be written.",\n+        outfile_path);\n+    return false;\n+  }\n+\n+  const u64 disc_size = infile->GetDataSize();\n+\n+  // These match the values used by standard WBFS tools (wwt, WBFS Manager)\n+  static constexpr u8 hd_sector_shift = 9;\n+  static constexpr u8 wbfs_sector_shift = 21;\n+  static constexpr u64 hd_sector_size = 1ull << hd_sector_shift;\n+  static constexpr u64 wbfs_sector_size = 1ull << wbfs_sector_shift;\n+\n+  const u64 blocks_per_disc = (disc_size + wbfs_sector_size - 1) / wbfs_sector_size;\n+  const u64 disc_info_size =\n+      Common::AlignUp(WII_DISC_HEADER_SIZE + blocks_per_disc * sizeof(u16), hd_sector_size);\n+\n+  // Read disc header (first 256 bytes contain disc_id, disc_num, title, etc.)\n+  std::vector<u8> disc_header(WII_DISC_HEADER_SIZE, 0);\n+  if (!infile->Read(0, WII_DISC_HEADER_SIZE, disc_header.data()))\n+  {\n+    PanicAlertFmtT("Failed to read from the input file \\"{0}\\".", infile_path);\n+    return false;\n+  }\n+\n+  // Use Volume for partition info and decrypted reads\n+  struct PartitionInfo\n+  {\n+    u64 data_offset;\n+    u64 data_size;\n+    Partition partition;\n+  };\n+  std::vector<PartitionInfo> partitions;\n+\n+  std::unique_ptr<VolumeDisc> volume = CreateDisc(infile_path);\n+  if (volume)\n+  {\n+    for (const Partition& partition : volume->GetPartitions())\n+    {\n+      const std::optional<u64> data_offset =\n+          volume->ReadSwappedAndShifted(partition.offset + 0x2B8, PARTITION_NONE);\n+      const std::optional<u64> data_size =\n+          volume->ReadSwappedAndShifted(partition.offset + 0x2BC, PARTITION_NONE);\n+      if (!data_offset || !data_size)\n+        continue;\n+\n+      PartitionInfo info;\n+      info.data_offset = partition.offset + *data_offset;\n+      info.data_size = *data_size;\n+      info.partition = partition;\n+      partitions.push_back(info);\n+    }\n+  }\n+\n+  // NKit v2 gap type bitmap: 1 bit per block, MSB-first, always sized for dual-layer\n+  const u64 gap_type_blocks = (DL_DVD_SIZE + wbfs_sector_size - 1) / wbfs_sector_size;\n+  const u64 gap_type_bytes = (gap_type_blocks + 7) / 8;\n+  std::vector<u8> gap_type(gap_type_bytes, 0);\n+\n+  // Compute data_start up front so we can write sectors during the scan\n+  const u64 data_start = Common::AlignUp(hd_sector_size + disc_info_size, wbfs_sector_size);\n+  const u16 wlba_base = static_cast<u16>(data_start / wbfs_sector_size);\n+\n+  // Single pass: scan, classify, hash, and write used sectors in one loop\n+  std::vector<u8> sector_buf(wbfs_sector_size, 0);\n+  std::vector<u16> wlba_table(blocks_per_disc, 0);\n+  u16 used_count = 0;\n+\n+  // NKit v2 stores four hash digests for verification\n+  auto sha1_ctx = Common::SHA1::CreateContext();\n+  u32 crc = Common::StartCRC32();\n+  mbedtls_md5_context md5_ctx{};\n+  mbedtls_md5_init(&md5_ctx);\n+  mbedtls_md5_starts_ret(&md5_ctx);\n+  XXH64_state_t* xxh_state = XXH64_createState();\n+  XXH64_reset(xxh_state, 0);\n+\n+  for (u64 i = 0; i < blocks_per_disc; i++)\n+  {\n+    if (i % 100 == 0)\n+    {\n+      const bool was_cancelled =\n+          !callback(Common::GetStringT("Converting"),\n+                    static_cast<float>(i) / static_cast<float>(blocks_per_disc));\n+      if (was_cancelled)\n+      {\n+        XXH64_freeState(xxh_state);\n+        mbedtls_md5_free(&md5_ctx);\n+        outfile.Close();\n+        File::Delete(outfile_path);\n+        return false;\n+      }\n+    }\n+\n+    const u64 offset = i * wbfs_sector_size;\n+    const size_t sz = static_cast<size_t>(std::min(wbfs_sector_size, disc_size - offset));\n+\n+    if (!infile->Read(offset, sz, sector_buf.data()))\n+    {\n+      PanicAlertFmtT("Failed to read from the input file \\"{0}\\".", infile_path);\n+      XXH64_freeState(xxh_state);\n+      mbedtls_md5_free(&md5_ctx);\n+      outfile.Close();\n+      File::Delete(outfile_path);\n+      return false;\n+    }\n+\n+    // Update all four hashes with the full disc data\n+    sha1_ctx->Update(sector_buf.data(), sz);\n+    crc = Common::UpdateCRC32(crc, sector_buf.data(), sz);\n+    mbedtls_md5_update_ret(&md5_ctx, sector_buf.data(), sz);\n+    XXH64_update(xxh_state, sector_buf.data(), sz);\n+\n+    // Find which partition (if any) this block belongs to\n+    const u32 start_sector = static_cast<u32>(offset / VolumeWii::BLOCK_TOTAL_SIZE);\n+    const u32 end_sector = static_cast<u32>((offset + sz) / VolumeWii::BLOCK_TOTAL_SIZE);\n+    const auto it = std::ranges::find_if(partitions, [&](const PartitionInfo& p) {\n+      const u32 p_start = static_cast<u32>(p.data_offset / VolumeWii::BLOCK_TOTAL_SIZE);\n+      const u32 p_end =\n+          static_cast<u32>((p.data_offset + p.data_size) / VolumeWii::BLOCK_TOTAL_SIZE);', 'path': 'Source/Core/DiscIO/WbfsBlob.cpp', 'commit_id': '24b41d58df2315831b74f76b95417f2739d02f9d', 'original_commit_id': '24b41d58df2315831b74f76b95417f2739d02f9d', 'user': {'login': 'thethiny', 'id': 6018214, 'node_id': 'MDQ6VXNlcjYwMTgyMTQ=', 'avatar_url': 'https://avatars.githubusercontent.com/u/6018214?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/thethiny', 'html_url': 'https://github.com/thethiny', 'followers_url': 'https://api.github.com/users/thethiny/followers', 'following_url': 'https://api.github.com/users/thethiny/following{/other_user}', 'gists_url': 'https://api.github.com/users/thethiny/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/thethiny/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/thethiny/subscriptions', 'organizations_url': 'https://api.github.com/users/thethiny/orgs', 'repos_url': 'https://api.github.com/users/thethiny/repos', 'events_url': 'https://api.github.com/users/thethiny/events{/privacy}', 'received_events_url': 'https://api.github.com/users/thethiny/received_events', 'type': 'User', 'user_view_type': 'public', 'site_admin': False}, 'body': 'this is an oversight on my end due to iterative coding. Noted', 'created_at': '2026-07-18T23:37:35Z', 'updated_at': '2026-07-18T23:37:35Z', 'html_url': 'https://github.com/dolphin-emu/dolphin/pull/14731#discussion_r3609419546', 'pull_request_url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/14731', '_links': {'self': {'href': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/comments/3609419546'}, 'html': {'href': 'https://github.com/dolphin-emu/dolphin/pull/14731#discussion_r3609419546'}, 'pull_request': {'href': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/14731'}}, 'reactions': {'url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/comments/3609419546/reactions', 'total_count': 0, '+1': 0, '-1': 0, 'laugh': 0, 'hooray': 0, 'confused': 0, 'heart': 0, 'rocket': 0, 'eyes': 0}, 'start_line': 519, 'original_start_line': 519, 'start_side': 'RIGHT', 'line': 524, 'original_line': 524, 'side': 'RIGHT', 'in_reply_to_id': 3609363364, 'author_association': 'NONE', 'original_position': 431, 'position': 431, 'subject_type': 'line'}, 'pull_request': {'url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/14731', 'id': 4056977334, 'node_id': 'PR_kwDOALCn2M7x0I-2', 'html_url': 'https://github.com/dolphin-emu/dolphin/pull/14731', 'diff_url': 'https://github.com/dolphin-emu/dolphin/pull/14731.diff', 'patch_url': 'https://github.com/dolphin-emu/dolphin/pull/14731.patch', 'issue_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/14731', 'number': 14731, 'state': 'open', 'locked': False, 'title': 'Convert To WBFS Support', 'user': {'login': 'thethiny', 'id': 6018214, 'node_id': 'MDQ6VXNlcjYwMTgyMTQ=', 'avatar_url': 'https://avatars.githubusercontent.com/u/6018214?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/thethiny', 'html_url': 'https://github.com/thethiny', 'followers_url': 'https://api.github.com/users/thethiny/followers', 'following_url': 'https://api.github.com/users/thethiny/following{/other_user}', 'gists_url': 'https://api.github.com/users/thethiny/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/thethiny/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/thethiny/subscriptions', 'organizations_url': 'https://api.github.com/users/thethiny/orgs', 'repos_url': 'https://api.github.com/users/thethiny/repos', 'events_url': 'https://api.github.com/users/thethiny/events{/privacy}', 'received_events_url': 'https://api.github.com/users/thethiny/received_events', 'type': 'User', 'user_view_type': 'public', 'site_admin': False}, 'body': "This PR introduces Conversion **to** WBFS support. WBFS is the format that is used by USB Loaders on a real Wii device.\r\n\r\n## Design decisions & hardcoded values\r\nThe writer uses fixed sector sizes that match what [libwbfs (the reference implementation by kwiirk)](https://github.com/kwiirk/wbfs/blob/master/libwbfs/libwbfs.c#L128-L134) computes for a standard single-layer Wii disc. These 2 hardcodes are stable and work correctly across all my testings.\r\n- HD sector shift: 9 (512 bytes)\r\n- WBFS sector shift: 21 (2 MiB)\r\nThese are not configurable via the UI. All existing WBFS tools use these values, and since the aim is to support USB Loaders then this has been tested and it is working on a real Wii.\r\n\r\nConverting from WBFS is not enabled. The existing `WbfsFileReader` reports `DataSizeType::UpperBound`, and `ShouldAllowConversion()` requires `Accurate`. I am able to support this but since it was hardcoded by the Dolphin team I thought a discussion is warranted.\r\n\r\n## Testing\r\n- Verified with DolphinTool header and DolphinTool verify\r\n- Verified with wit FILETYPE and wit DUMP (Wiimm's ISO Tools recognizes valid WBFS structure, partitions, encryption)\r\n- Tested ISO to WBFS and RVZ to WBFS conversions\r\n- Output file sizes match Wii Backup Manager when scrubbing is enabled (~0.1% difference), works when scrubbing is disabled.\r\n- Output WBFS files play correctly in Dolphin\r\n- Output WBFS files play correctly on a real Wii using USB Loader GX e25c4f3\r\n", 'created_at': '2026-07-15T01:16:25Z', 'updated_at': '2026-07-18T23:36:11Z', 'closed_at': None, 'merged_at': None, 'merge_commit_sha': '228f93416dd80eb09da834ad7852c8eaa4d9212b', 'assignees': [], 'requested_reviewers': [], 'requested_teams': [], 'labels': [], 'milestone': None, 'draft': False, 'commits_url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/14731/commits', 'review_comments_url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/14731/comments', 'review_comment_url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/comments{/number}', 'comments_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/14731/comments', 'statuses_url': 'https://api.github.com/repos/dolphin-emu/dolphin/statuses/24b41d58df2315831b74f76b95417f2739d02f9d', 'head': {'label': 'thethiny:wbfs-conversion', 'ref': 'wbfs-conversion', 'sha': '24b41d58df2315831b74f76b95417f2739d02f9d', 'user': {'login': 'thethiny', 'id': 6018214, 'node_id': 'MDQ6VXNlcjYwMTgyMTQ=', 'avatar_url': 'https://avatars.githubusercontent.com/u/6018214?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/thethiny', 'html_url': 'https://github.com/thethiny', 'followers_url': 'https://api.github.com/users/thethiny/followers', 'following_url': 'https://api.github.com/users/thethiny/following{/other_user}', 'gists_url': 'https://api.github.com/users/thethiny/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/thethiny/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/thethiny/subscriptions', 'organizations_url': 'https://api.github.com/users/thethiny/orgs', 'repos_url': 'https://api.github.com/users/thethiny/repos', 'events_url': 'https://api.github.com/users/thethiny/events{/privacy}', 'received_events_url': 'https://api.github.com/users/thethiny/received_events', 'type': 'User', 'user_view_type': 'public', 'site_admin': False}, 'repo': {'id': 1298654395, 'node_id': 'R_kgDOTWfkuw', 'name': 'dolphin', 'full_name': 'thethiny/dolphin', 'private': False, 'owner': {'login': 'thethiny', 'id': 6018214, 'node_id': 'MDQ6VXNlcjYwMTgyMTQ=', 'avatar_url': 'https://avatars.githubusercontent.com/u/6018214?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/thethiny', 'html_url': 'https://github.com/thethiny', 'followers_url': 'https://api.github.com/users/thethiny/followers', 'following_url': 'https://api.github.com/users/thethiny/following{/other_user}', 'gists_url': 'https://api.github.com/users/thethiny/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/thethiny/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/thethiny/subscriptions', 'organizations_url': 'https://api.github.com/users/thethiny/orgs', 'repos_url': 'https://api.github.com/users/thethiny/repos', 'events_url': 'https://api.github.com/users/thethiny/events{/privacy}', 'received_events_url': 'https://api.github.com/users/thethiny/received_events', 'type': 'User', 'user_view_type': 'public', 'site_admin': False}, 'html_url': 'https://github.com/thethiny/dolphin', 'description': 'Dolphin is a GameCube / Wii emulator, allowing you to play games for these two platforms on PC with improvements.', 'fork': True, 'url': 'https://api.github.com/repos/thethiny/dolphin', 'forks_url': 'https://api.github.com/repos/thethiny/dolphin/forks', 'keys_url': 'https://api.github.com/repos/thethiny/dolphin/keys{/key_id}', 'collaborators_url': 'https://api.github.com/repos/thethiny/dolphin/collaborators{/collaborator}', 'teams_url': 'https://api.github.com/repos/thethiny/dolphin/teams', 'hooks_url': 'https://api.github.com/repos/thethiny/dolphin/hooks', 'issue_events_url': 'https://api.github.com/repos/thethiny/dolphin/issues/events{/number}', 'events_url': 'https://api.github.com/repos/thethiny/dolphin/events', 'assignees_url': 'https://api.github.com/repos/thethiny/dolphin/assignees{/user}', 'branches_url': 'https://api.github.com/repos/thethiny/dolphin/branches{/branch}', 'tags_url': 'https://api.github.com/repos/thethiny/dolphin/tags', 'blobs_url': 'https://api.github.com/repos/thethiny/dolphin/git/blobs{/sha}', 'git_tags_url': 'https://api.github.com/repos/thethiny/dolphin/git/tags{/sha}', 'git_refs_url': 'https://api.github.com/repos/thethiny/dolphin/git/refs{/sha}', 'trees_url': 'https://api.github.com/repos/thethiny/dolphin/git/trees{/sha}', 'statuses_url': 'https://api.github.com/repos/thethiny/dolphin/statuses/{sha}', 'languages_url': 'https://api.github.com/repos/thethiny/dolphin/languages', 'stargazers_url': 'https://api.github.com/repos/thethiny/dolphin/stargazers', 'contributors_url': 'https://api.github.com/repos/thethiny/dolphin/contributors', 'subscribers_url': 'https://api.github.com/repos/thethiny/dolphin/subscribers', 'subscription_url': 'https://api.github.com/repos/thethiny/dolphin/subscription', 'commits_url': 'https://api.github.com/repos/thethiny/dolphin/commits{/sha}', 'git_commits_url': 'https://api.github.com/repos/thethiny/dolphin/git/commits{/sha}', 'comments_url': 'https://api.github.com/repos/thethiny/dolphin/comments{/number}', 'issue_comment_url': 'https://api.github.com/repos/thethiny/dolphin/issues/comments{/number}', 'contents_url': 'https://api.github.com/repos/thethiny/dolphin/contents/{+path}', 'compare_url': 'https://api.github.com/repos/thethiny/dolphin/compare/{base}...{head}', 'merges_url': 'https://api.github.com/repos/thethiny/dolphin/merges', 'archive_url': 'https://api.github.com/repos/thethiny/dolphin/{archive_format}{/ref}', 'downloads_url': 'https://api.github.com/repos/thethiny/dolphin/downloads', 'issues_url': 'https://api.github.com/repos/thethiny/dolphin/issues{/number}', 'pulls_url': 'https://api.github.com/repos/thethiny/dolphin/pulls{/number}', 'milestones_url': 'https://api.github.com/repos/thethiny/dolphin/milestones{/number}', 'notifications_url': 'https://api.github.com/repos/thethiny/dolphin/notifications{?since,all,participating}', 'labels_url': 'https://api.github.com/repos/thethiny/dolphin/labels{/name}', 'releases_url': 'https://api.github.com/repos/thethiny/dolphin/releases{/id}', 'deployments_url': 'https://api.github.com/repos/thethiny/dolphin/deployments', 'created_at': '2026-07-12T22:09:13Z', 'updated_at': '2026-07-12T22:09:13Z', 'pushed_at': '2026-07-18T20:35:03Z', 'git_url': 'git://github.com/thethiny/dolphin.git', 'ssh_url': 'git@github.com:thethiny/dolphin.git', 'clone_url': 'https://github.com/thethiny/dolphin.git', 'svn_url': 'https://github.com/thethiny/dolphin', 'homepage': 'https://dolphin-emu.org', 'size': 515471, 'stargazers_count': 0, 'watchers_count': 0, 'language': None, 'has_issues': False, 'has_projects': True, 'has_downloads': True, 'has_wiki': True, 'has_pages': False, 'has_discussions': False, 'forks_count': 0, 'mirror_url': None, 'archived': False, 'disabled': False, 'open_issues_count': 0, 'license': {'key': 'other', 'name': 'Other', 'spdx_id': 'NOASSERTION', 'url': None, 'node_id': 'MDc6TGljZW5zZTA='}, 'allow_forking': True, 'is_template': False, 'web_commit_signoff_required': False, 'has_pull_requests': True, 'pull_request_creation_policy': 'all', 'topics': [], 'visibility': 'public', 'forks': 0, 'open_issues': 0, 'watchers': 0, 'default_branch': 'master', 'allow_squash_merge': True, 'allow_merge_commit': True, 'allow_rebase_merge': True, 'allow_auto_merge': False, 'delete_branch_on_merge': False, 'allow_update_branch': False, 'use_squash_pr_title_as_default': False, 'squash_merge_commit_message': 'COMMIT_MESSAGES', 'squash_merge_commit_title': 'COMMIT_OR_PR_TITLE', 'merge_commit_message': 'PR_TITLE', 'merge_commit_title': 'MERGE_MESSAGE'}}, 'base': {'label': 'dolphin-emu:master', 'ref': 'master', 'sha': 'd3b2943807dd0073f7767947466dd73cccfef319', 'user': {'login': 'dolphin-emu', 'id': 5050316, 'node_id': 'MDEyOk9yZ2FuaXphdGlvbjUwNTAzMTY=', 'avatar_url': 'https://avatars.githubusercontent.com/u/5050316?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/dolphin-emu', 'html_url': 'https://github.com/dolphin-emu', 'followers_url': 'https://api.github.com/users/dolphin-emu/followers', 'following_url': 'https://api.github.com/users/dolphin-emu/following{/other_user}', 'gists_url': 'https://api.github.com/users/dolphin-emu/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/dolphin-emu/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/dolphin-emu/subscriptions', 'organizations_url': 'https://api.github.com/users/dolphin-emu/orgs', 'repos_url': 'https://api.github.com/users/dolphin-emu/repos', 'events_url': 'https://api.github.com/users/dolphin-emu/events{/privacy}', 'received_events_url': 'https://api.github.com/users/dolphin-emu/received_events', 'type': 'Organization', 'user_view_type': 'public', 'site_admin': False}, 'repo': {'id': 11577304, 'node_id': 'MDEwOlJlcG9zaXRvcnkxMTU3NzMwNA==', 'name': 'dolphin', 'full_name': 'dolphin-emu/dolphin', 'private': False, 'owner': {'login': 'dolphin-emu', 'id': 5050316, 'node_id': 'MDEyOk9yZ2FuaXphdGlvbjUwNTAzMTY=', 'avatar_url': 'https://avatars.githubusercontent.com/u/5050316?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/dolphin-emu', 'html_url': 'https://github.com/dolphin-emu', 'followers_url': 'https://api.github.com/users/dolphin-emu/followers', 'following_url': 'https://api.github.com/users/dolphin-emu/following{/other_user}', 'gists_url': 'https://api.github.com/users/dolphin-emu/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/dolphin-emu/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/dolphin-emu/subscriptions', 'organizations_url': 'https://api.github.com/users/dolphin-emu/orgs', 'repos_url': 'https://api.github.com/users/dolphin-emu/repos', 'events_url': 'https://api.github.com/users/dolphin-emu/events{/privacy}', 'received_events_url': 'https://api.github.com/users/dolphin-emu/received_events', 'type': 'Organization', 'user_view_type': 'public', 'site_admin': False}, 'html_url': 'https://github.com/dolphin-emu/dolphin', 'description': 'Dolphin is a GameCube / Wii emulator, allowing you to play games for these two platforms on PC with improvements.', 'fork': False, 'url': 'https://api.github.com/repos/dolphin-emu/dolphin', 'forks_url': 'https://api.github.com/repos/dolphin-emu/dolphin/forks', 'keys_url': 'https://api.github.com/repos/dolphin-emu/dolphin/keys{/key_id}', 'collaborators_url': 'https://api.github.com/repos/dolphin-emu/dolphin/collaborators{/collaborator}', 'teams_url': 'https://api.github.com/repos/dolphin-emu/dolphin/teams', 'hooks_url': 'https://api.github.com/repos/dolphin-emu/dolphin/hooks', 'issue_events_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/events{/number}', 'events_url': 'https://api.github.com/repos/dolphin-emu/dolphin/events', 'assignees_url': 'https://api.github.com/repos/dolphin-emu/dolphin/assignees{/user}', 'branches_url': 'https://api.github.com/repos/dolphin-emu/dolphin/branches{/branch}', 'tags_url': 'https://api.github.com/repos/dolphin-emu/dolphin/tags', 'blobs_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/blobs{/sha}', 'git_tags_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/tags{/sha}', 'git_refs_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/refs{/sha}', 'trees_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/trees{/sha}', 'statuses_url': 'https://api.github.com/repos/dolphin-emu/dolphin/statuses/{sha}', 'languages_url': 'https://api.github.com/repos/dolphin-emu/dolphin/languages', 'stargazers_url': 'https://api.github.com/repos/dolphin-emu/dolphin/stargazers', 'contributors_url': 'https://api.github.com/repos/dolphin-emu/dolphin/contributors', 'subscribers_url': 'https://api.github.com/repos/dolphin-emu/dolphin/subscribers', 'subscription_url': 'https://api.github.com/repos/dolphin-emu/dolphin/subscription', 'commits_url': 'https://api.github.com/repos/dolphin-emu/dolphin/commits{/sha}', 'git_commits_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/commits{/sha}', 'comments_url': 'https://api.github.com/repos/dolphin-emu/dolphin/comments{/number}', 'issue_comment_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/comments{/number}', 'contents_url': 'https://api.github.com/repos/dolphin-emu/dolphin/contents/{+path}', 'compare_url': 'https://api.github.com/repos/dolphin-emu/dolphin/compare/{base}...{head}', 'merges_url': 'https://api.github.com/repos/dolphin-emu/dolphin/merges', 'archive_url': 'https://api.github.com/repos/dolphin-emu/dolphin/{archive_format}{/ref}', 'downloads_url': 'https://api.github.com/repos/dolphin-emu/dolphin/downloads', 'issues_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues{/number}', 'pulls_url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls{/number}', 'milestones_url': 'https://api.github.com/repos/dolphin-emu/dolphin/milestones{/number}', 'notifications_url': 'https://api.github.com/repos/dolphin-emu/dolphin/notifications{?since,all,participating}', 'labels_url': 'https://api.github.com/repos/dolphin-emu/dolphin/labels{/name}', 'releases_url': 'https://api.github.com/repos/dolphin-emu/dolphin/releases{/id}', 'deployments_url': 'https://api.github.com/repos/dolphin-emu/dolphin/deployments', 'created_at': '2013-07-22T09:07:57Z', 'updated_at': '2026-07-18T23:13:54Z', 'pushed_at': '2026-07-18T10:34:54Z', 'git_url': 'git://github.com/dolphin-emu/dolphin.git', 'ssh_url': 'git@github.com:dolphin-emu/dolphin.git', 'clone_url': 'https://github.com/dolphin-emu/dolphin.git', 'svn_url': 'https://github.com/dolphin-emu/dolphin', 'homepage': 'https://dolphin-emu.org', 'size': 558448, 'stargazers_count': 15273, 'watchers_count': 15273, 'language': 'C++', 'has_issues': False, 'has_projects': False, 'has_downloads': True, 'has_wiki': True, 'has_pages': False, 'has_discussions': False, 'forks_count': 3162, 'mirror_url': None, 'archived': False, 'disabled': False, 'open_issues_count': 446, 'license': {'key': 'other', 'name': 'Other', 'spdx_id': 'NOASSERTION', 'url': None, 'node_id': 'MDc6TGljZW5zZTA='}, 'allow_forking': True, 'is_template': False, 'web_commit_signoff_required': False, 'has_pull_requests': True, 'pull_request_creation_policy': 'all', 'topics': ['cpp', 'emulation', 'emulator', 'gamecube', 'wii'], 'visibility': 'public', 'forks': 3162, 'open_issues': 446, 'watchers': 15273, 'default_branch': 'master', 'allow_squash_merge': False, 'allow_merge_commit': True, 'allow_rebase_merge': False, 'allow_auto_merge': False, 'delete_branch_on_merge': False, 'allow_update_branch': False, 'use_squash_pr_title_as_default': False, 'squash_merge_commit_message': 'COMMIT_MESSAGES', 'squash_merge_commit_title': 'COMMIT_OR_PR_TITLE', 'merge_commit_message': 'PR_TITLE', 'merge_commit_title': 'MERGE_MESSAGE'}}, '_links': {'self': {'href': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/14731'}, 'html': {'href': 'https://github.com/dolphin-emu/dolphin/pull/14731'}, 'issue': {'href': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/14731'}, 'comments': {'href': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/14731/comments'}, 'review_comments': {'href': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/14731/comments'}, 'review_comment': {'href': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/comments{/number}'}, 'commits': {'href': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/14731/commits'}, 'statuses': {'href': 'https://api.github.com/repos/dolphin-emu/dolphin/statuses/24b41d58df2315831b74f76b95417f2739d02f9d'}}, 'author_association': 'NONE', 'auto_merge': None, 'assignee': None, 'active_lock_reason': None}, 'repository': {'id': 11577304, 'node_id': 'MDEwOlJlcG9zaXRvcnkxMTU3NzMwNA==', 'name': 'dolphin', 'full_name': 'dolphin-emu/dolphin', 'private': False, 'owner': {'login': 'dolphin-emu', 'id': 5050316, 'node_id': 'MDEyOk9yZ2FuaXphdGlvbjUwNTAzMTY=', 'avatar_url': 'https://avatars.githubusercontent.com/u/5050316?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/dolphin-emu', 'html_url': 'https://github.com/dolphin-emu', 'followers_url': 'https://api.github.com/users/dolphin-emu/followers', 'following_url': 'https://api.github.com/users/dolphin-emu/following{/other_user}', 'gists_url': 'https://api.github.com/users/dolphin-emu/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/dolphin-emu/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/dolphin-emu/subscriptions', 'organizations_url': 'https://api.github.com/users/dolphin-emu/orgs', 'repos_url': 'https://api.github.com/users/dolphin-emu/repos', 'events_url': 'https://api.github.com/users/dolphin-emu/events{/privacy}', 'received_events_url': 'https://api.github.com/users/dolphin-emu/received_events', 'type': 'Organization', 'user_view_type': 'public', 'site_admin': False}, 'html_url': 'https://github.com/dolphin-emu/dolphin', 'description': 'Dolphin is a GameCube / Wii emulator, allowing you to play games for these two platforms on PC with improvements.', 'fork': False, 'url': 'https://api.github.com/repos/dolphin-emu/dolphin', 'forks_url': 'https://api.github.com/repos/dolphin-emu/dolphin/forks', 'keys_url': 'https://api.github.com/repos/dolphin-emu/dolphin/keys{/key_id}', 'collaborators_url': 'https://api.github.com/repos/dolphin-emu/dolphin/collaborators{/collaborator}', 'teams_url': 'https://api.github.com/repos/dolphin-emu/dolphin/teams', 'hooks_url': 'https://api.github.com/repos/dolphin-emu/dolphin/hooks', 'issue_events_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/events{/number}', 'events_url': 'https://api.github.com/repos/dolphin-emu/dolphin/events', 'assignees_url': 'https://api.github.com/repos/dolphin-emu/dolphin/assignees{/user}', 'branches_url': 'https://api.github.com/repos/dolphin-emu/dolphin/branches{/branch}', 'tags_url': 'https://api.github.com/repos/dolphin-emu/dolphin/tags', 'blobs_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/blobs{/sha}', 'git_tags_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/tags{/sha}', 'git_refs_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/refs{/sha}', 'trees_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/trees{/sha}', 'statuses_url': 'https://api.github.com/repos/dolphin-emu/dolphin/statuses/{sha}', 'languages_url': 'https://api.github.com/repos/dolphin-emu/dolphin/languages', 'stargazers_url': 'https://api.github.com/repos/dolphin-emu/dolphin/stargazers', 'contributors_url': 'https://api.github.com/repos/dolphin-emu/dolphin/contributors', 'subscribers_url': 'https://api.github.com/repos/dolphin-emu/dolphin/subscribers', 'subscription_url': 'https://api.github.com/repos/dolphin-emu/dolphin/subscription', 'commits_url': 'https://api.github.com/repos/dolphin-emu/dolphin/commits{/sha}', 'git_commits_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/commits{/sha}', 'comments_url': 'https://api.github.com/repos/dolphin-emu/dolphin/comments{/number}', 'issue_comment_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/comments{/number}', 'contents_url': 'https://api.github.com/repos/dolphin-emu/dolphin/contents/{+path}', 'compare_url': 'https://api.github.com/repos/dolphin-emu/dolphin/compare/{base}...{head}', 'merges_url': 'https://api.github.com/repos/dolphin-emu/dolphin/merges', 'archive_url': 'https://api.github.com/repos/dolphin-emu/dolphin/{archive_format}{/ref}', 'downloads_url': 'https://api.github.com/repos/dolphin-emu/dolphin/downloads', 'issues_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues{/number}', 'pulls_url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls{/number}', 'milestones_url': 'https://api.github.com/repos/dolphin-emu/dolphin/milestones{/number}', 'notifications_url': 'https://api.github.com/repos/dolphin-emu/dolphin/notifications{?since,all,participating}', 'labels_url': 'https://api.github.com/repos/dolphin-emu/dolphin/labels{/name}', 'releases_url': 'https://api.github.com/repos/dolphin-emu/dolphin/releases{/id}', 'deployments_url': 'https://api.github.com/repos/dolphin-emu/dolphin/deployments', 'created_at': '2013-07-22T09:07:57Z', 'updated_at': '2026-07-18T23:13:54Z', 'pushed_at': '2026-07-18T10:34:54Z', 'git_url': 'git://github.com/dolphin-emu/dolphin.git', 'ssh_url': 'git@github.com:dolphin-emu/dolphin.git', 'clone_url': 'https://github.com/dolphin-emu/dolphin.git', 'svn_url': 'https://github.com/dolphin-emu/dolphin', 'homepage': 'https://dolphin-emu.org', 'size': 558448, 'stargazers_count': 15273, 'watchers_count': 15273, 'language': 'C++', 'has_issues': False, 'has_projects': False, 'has_downloads': True, 'has_wiki': True, 'has_pages': False, 'has_discussions': False, 'forks_count': 3162, 'mirror_url': None, 'archived': False, 'disabled': False, 'open_issues_count': 446, 'license': {'key': 'other', 'name': 'Other', 'spdx_id': 'NOASSERTION', 'url': None, 'node_id': 'MDc6TGljZW5zZTA='}, 'allow_forking': True, 'is_template': False, 'web_commit_signoff_required': False, 'has_pull_requests': True, 'pull_request_creation_policy': 'all', 'topics': ['cpp', 'emulation', 'emulator', 'gamecube', 'wii'], 'visibility': 'public', 'forks': 3162, 'open_issues': 446, 'watchers': 15273, 'default_branch': 'master', 'custom_properties': {}}, 'organization': {'login': 'dolphin-emu', 'id': 5050316, 'node_id': 'MDEyOk9yZ2FuaXphdGlvbjUwNTAzMTY=', 'url': 'https://api.github.com/orgs/dolphin-emu', 'repos_url': 'https://api.github.com/orgs/dolphin-emu/repos', 'events_url': 'https://api.github.com/orgs/dolphin-emu/events', 'hooks_url': 'https://api.github.com/orgs/dolphin-emu/hooks', 'issues_url': 'https://api.github.com/orgs/dolphin-emu/issues', 'members_url': 'https://api.github.com/orgs/dolphin-emu/members{/member}', 'public_members_url': 'https://api.github.com/orgs/dolphin-emu/public_members{/member}', 'avatar_url': 'https://avatars.githubusercontent.com/u/5050316?v=4', 'description': ''}, 'sender': {'login': 'thethiny', 'id': 6018214, 'node_id': 'MDQ6VXNlcjYwMTgyMTQ=', 'avatar_url': 'https://avatars.githubusercontent.com/u/6018214?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/thethiny', 'html_url': 'https://github.com/thethiny', 'followers_url': 'https://api.github.com/users/thethiny/followers', 'following_url': 'https://api.github.com/users/thethiny/following{/other_user}', 'gists_url': 'https://api.github.com/users/thethiny/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/thethiny/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/thethiny/subscriptions', 'organizations_url': 'https://api.github.com/users/thethiny/orgs', 'repos_url': 'https://api.github.com/users/thethiny/repos', 'events_url': 'https://api.github.com/users/thethiny/events{/privacy}', 'received_events_url': 'https://api.github.com/users/thethiny/received_events', 'type': 'User', 'user_view_type': 'public', 'site_admin': False}, 'installation': {'id': 35437981, 'node_id': 'MDIzOkludGVncmF0aW9uSW5zdGFsbGF0aW9uMzU0Mzc5ODE='}}, 'type': 'raw_gh_hook'}
2026-07-18T23:37:37.476236	{'source': 'ghhookparser', 'repo': 'dolphin-emu/dolphin', 'author': 'thethiny', 'action': 'created', 'id': 14731, 'hash': '24b41d58df2315831b74f76b95417f2739d02f9d', 'url': 'https://github.com/dolphin-emu/dolphin/pull/14731#discussion_r3609419546', 'is_part_of_review': False, 'type': 'gh_pull_request_comment'}
2026-07-18T23:37:37.379719	{'source': 'webserver', 'gh_type': 'pull_request_review', 'raw': {'action': 'submitted', 'review': {'id': 4729501733, 'node_id': 'PRR_kwDOALCn2M8AAAABGeZ4JQ', 'user': {'login': 'thethiny', 'id': 6018214, 'node_id': 'MDQ6VXNlcjYwMTgyMTQ=', 'avatar_url': 'https://avatars.githubusercontent.com/u/6018214?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/thethiny', 'html_url': 'https://github.com/thethiny', 'followers_url': 'https://api.github.com/users/thethiny/followers', 'following_url': 'https://api.github.com/users/thethiny/following{/other_user}', 'gists_url': 'https://api.github.com/users/thethiny/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/thethiny/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/thethiny/subscriptions', 'organizations_url': 'https://api.github.com/users/thethiny/orgs', 'repos_url': 'https://api.github.com/users/thethiny/repos', 'events_url': 'https://api.github.com/users/thethiny/events{/privacy}', 'received_events_url': 'https://api.github.com/users/thethiny/received_events', 'type': 'User', 'user_view_type': 'public', 'site_admin': False}, 'body': None, 'commit_id': '24b41d58df2315831b74f76b95417f2739d02f9d', 'state': 'commented', 'html_url': 'https://github.com/dolphin-emu/dolphin/pull/14731#pullrequestreview-4729501733', 'pull_request_url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/14731', '_links': {'html': {'href': 'https://github.com/dolphin-emu/dolphin/pull/14731#pullrequestreview-4729501733'}, 'pull_request': {'href': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/14731'}}, 'submitted_at': '2026-07-18T23:37:35Z', 'updated_at': '2026-07-18T23:37:35Z', 'author_association': 'NONE'}, 'pull_request': {'url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/14731', 'id': 4056977334, 'node_id': 'PR_kwDOALCn2M7x0I-2', 'html_url': 'https://github.com/dolphin-emu/dolphin/pull/14731', 'diff_url': 'https://github.com/dolphin-emu/dolphin/pull/14731.diff', 'patch_url': 'https://github.com/dolphin-emu/dolphin/pull/14731.patch', 'issue_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/14731', 'number': 14731, 'state': 'open', 'locked': False, 'title': 'Convert To WBFS Support', 'user': {'login': 'thethiny', 'id': 6018214, 'node_id': 'MDQ6VXNlcjYwMTgyMTQ=', 'avatar_url': 'https://avatars.githubusercontent.com/u/6018214?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/thethiny', 'html_url': 'https://github.com/thethiny', 'followers_url': 'https://api.github.com/users/thethiny/followers', 'following_url': 'https://api.github.com/users/thethiny/following{/other_user}', 'gists_url': 'https://api.github.com/users/thethiny/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/thethiny/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/thethiny/subscriptions', 'organizations_url': 'https://api.github.com/users/thethiny/orgs', 'repos_url': 'https://api.github.com/users/thethiny/repos', 'events_url': 'https://api.github.com/users/thethiny/events{/privacy}', 'received_events_url': 'https://api.github.com/users/thethiny/received_events', 'type': 'User', 'user_view_type': 'public', 'site_admin': False}, 'body': "This PR introduces Conversion **to** WBFS support. WBFS is the format that is used by USB Loaders on a real Wii device.\r\n\r\n## Design decisions & hardcoded values\r\nThe writer uses fixed sector sizes that match what [libwbfs (the reference implementation by kwiirk)](https://github.com/kwiirk/wbfs/blob/master/libwbfs/libwbfs.c#L128-L134) computes for a standard single-layer Wii disc. These 2 hardcodes are stable and work correctly across all my testings.\r\n- HD sector shift: 9 (512 bytes)\r\n- WBFS sector shift: 21 (2 MiB)\r\nThese are not configurable via the UI. All existing WBFS tools use these values, and since the aim is to support USB Loaders then this has been tested and it is working on a real Wii.\r\n\r\nConverting from WBFS is not enabled. The existing `WbfsFileReader` reports `DataSizeType::UpperBound`, and `ShouldAllowConversion()` requires `Accurate`. I am able to support this but since it was hardcoded by the Dolphin team I thought a discussion is warranted.\r\n\r\n## Testing\r\n- Verified with DolphinTool header and DolphinTool verify\r\n- Verified with wit FILETYPE and wit DUMP (Wiimm's ISO Tools recognizes valid WBFS structure, partitions, encryption)\r\n- Tested ISO to WBFS and RVZ to WBFS conversions\r\n- Output file sizes match Wii Backup Manager when scrubbing is enabled (~0.1% difference), works when scrubbing is disabled.\r\n- Output WBFS files play correctly in Dolphin\r\n- Output WBFS files play correctly on a real Wii using USB Loader GX e25c4f3\r\n", 'created_at': '2026-07-15T01:16:25Z', 'updated_at': '2026-07-18T23:36:11Z', 'closed_at': None, 'merged_at': None, 'merge_commit_sha': '228f93416dd80eb09da834ad7852c8eaa4d9212b', 'assignees': [], 'requested_reviewers': [], 'requested_teams': [], 'labels': [], 'milestone': None, 'draft': False, 'commits_url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/14731/commits', 'review_comments_url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/14731/comments', 'review_comment_url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/comments{/number}', 'comments_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/14731/comments', 'statuses_url': 'https://api.github.com/repos/dolphin-emu/dolphin/statuses/24b41d58df2315831b74f76b95417f2739d02f9d', 'head': {'label': 'thethiny:wbfs-conversion', 'ref': 'wbfs-conversion', 'sha': '24b41d58df2315831b74f76b95417f2739d02f9d', 'user': {'login': 'thethiny', 'id': 6018214, 'node_id': 'MDQ6VXNlcjYwMTgyMTQ=', 'avatar_url': 'https://avatars.githubusercontent.com/u/6018214?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/thethiny', 'html_url': 'https://github.com/thethiny', 'followers_url': 'https://api.github.com/users/thethiny/followers', 'following_url': 'https://api.github.com/users/thethiny/following{/other_user}', 'gists_url': 'https://api.github.com/users/thethiny/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/thethiny/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/thethiny/subscriptions', 'organizations_url': 'https://api.github.com/users/thethiny/orgs', 'repos_url': 'https://api.github.com/users/thethiny/repos', 'events_url': 'https://api.github.com/users/thethiny/events{/privacy}', 'received_events_url': 'https://api.github.com/users/thethiny/received_events', 'type': 'User', 'user_view_type': 'public', 'site_admin': False}, 'repo': {'id': 1298654395, 'node_id': 'R_kgDOTWfkuw', 'name': 'dolphin', 'full_name': 'thethiny/dolphin', 'private': False, 'owner': {'login': 'thethiny', 'id': 6018214, 'node_id': 'MDQ6VXNlcjYwMTgyMTQ=', 'avatar_url': 'https://avatars.githubusercontent.com/u/6018214?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/thethiny', 'html_url': 'https://github.com/thethiny', 'followers_url': 'https://api.github.com/users/thethiny/followers', 'following_url': 'https://api.github.com/users/thethiny/following{/other_user}', 'gists_url': 'https://api.github.com/users/thethiny/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/thethiny/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/thethiny/subscriptions', 'organizations_url': 'https://api.github.com/users/thethiny/orgs', 'repos_url': 'https://api.github.com/users/thethiny/repos', 'events_url': 'https://api.github.com/users/thethiny/events{/privacy}', 'received_events_url': 'https://api.github.com/users/thethiny/received_events', 'type': 'User', 'user_view_type': 'public', 'site_admin': False}, 'html_url': 'https://github.com/thethiny/dolphin', 'description': 'Dolphin is a GameCube / Wii emulator, allowing you to play games for these two platforms on PC with improvements.', 'fork': True, 'url': 'https://api.github.com/repos/thethiny/dolphin', 'forks_url': 'https://api.github.com/repos/thethiny/dolphin/forks', 'keys_url': 'https://api.github.com/repos/thethiny/dolphin/keys{/key_id}', 'collaborators_url': 'https://api.github.com/repos/thethiny/dolphin/collaborators{/collaborator}', 'teams_url': 'https://api.github.com/repos/thethiny/dolphin/teams', 'hooks_url': 'https://api.github.com/repos/thethiny/dolphin/hooks', 'issue_events_url': 'https://api.github.com/repos/thethiny/dolphin/issues/events{/number}', 'events_url': 'https://api.github.com/repos/thethiny/dolphin/events', 'assignees_url': 'https://api.github.com/repos/thethiny/dolphin/assignees{/user}', 'branches_url': 'https://api.github.com/repos/thethiny/dolphin/branches{/branch}', 'tags_url': 'https://api.github.com/repos/thethiny/dolphin/tags', 'blobs_url': 'https://api.github.com/repos/thethiny/dolphin/git/blobs{/sha}', 'git_tags_url': 'https://api.github.com/repos/thethiny/dolphin/git/tags{/sha}', 'git_refs_url': 'https://api.github.com/repos/thethiny/dolphin/git/refs{/sha}', 'trees_url': 'https://api.github.com/repos/thethiny/dolphin/git/trees{/sha}', 'statuses_url': 'https://api.github.com/repos/thethiny/dolphin/statuses/{sha}', 'languages_url': 'https://api.github.com/repos/thethiny/dolphin/languages', 'stargazers_url': 'https://api.github.com/repos/thethiny/dolphin/stargazers', 'contributors_url': 'https://api.github.com/repos/thethiny/dolphin/contributors', 'subscribers_url': 'https://api.github.com/repos/thethiny/dolphin/subscribers', 'subscription_url': 'https://api.github.com/repos/thethiny/dolphin/subscription', 'commits_url': 'https://api.github.com/repos/thethiny/dolphin/commits{/sha}', 'git_commits_url': 'https://api.github.com/repos/thethiny/dolphin/git/commits{/sha}', 'comments_url': 'https://api.github.com/repos/thethiny/dolphin/comments{/number}', 'issue_comment_url': 'https://api.github.com/repos/thethiny/dolphin/issues/comments{/number}', 'contents_url': 'https://api.github.com/repos/thethiny/dolphin/contents/{+path}', 'compare_url': 'https://api.github.com/repos/thethiny/dolphin/compare/{base}...{head}', 'merges_url': 'https://api.github.com/repos/thethiny/dolphin/merges', 'archive_url': 'https://api.github.com/repos/thethiny/dolphin/{archive_format}{/ref}', 'downloads_url': 'https://api.github.com/repos/thethiny/dolphin/downloads', 'issues_url': 'https://api.github.com/repos/thethiny/dolphin/issues{/number}', 'pulls_url': 'https://api.github.com/repos/thethiny/dolphin/pulls{/number}', 'milestones_url': 'https://api.github.com/repos/thethiny/dolphin/milestones{/number}', 'notifications_url': 'https://api.github.com/repos/thethiny/dolphin/notifications{?since,all,participating}', 'labels_url': 'https://api.github.com/repos/thethiny/dolphin/labels{/name}', 'releases_url': 'https://api.github.com/repos/thethiny/dolphin/releases{/id}', 'deployments_url': 'https://api.github.com/repos/thethiny/dolphin/deployments', 'created_at': '2026-07-12T22:09:13Z', 'updated_at': '2026-07-12T22:09:13Z', 'pushed_at': '2026-07-18T20:35:03Z', 'git_url': 'git://github.com/thethiny/dolphin.git', 'ssh_url': 'git@github.com:thethiny/dolphin.git', 'clone_url': 'https://github.com/thethiny/dolphin.git', 'svn_url': 'https://github.com/thethiny/dolphin', 'homepage': 'https://dolphin-emu.org', 'size': 515471, 'stargazers_count': 0, 'watchers_count': 0, 'language': None, 'has_issues': False, 'has_projects': True, 'has_downloads': True, 'has_wiki': True, 'has_pages': False, 'has_discussions': False, 'forks_count': 0, 'mirror_url': None, 'archived': False, 'disabled': False, 'open_issues_count': 0, 'license': {'key': 'other', 'name': 'Other', 'spdx_id': 'NOASSERTION', 'url': None, 'node_id': 'MDc6TGljZW5zZTA='}, 'allow_forking': True, 'is_template': False, 'web_commit_signoff_required': False, 'has_pull_requests': True, 'pull_request_creation_policy': 'all', 'topics': [], 'visibility': 'public', 'forks': 0, 'open_issues': 0, 'watchers': 0, 'default_branch': 'master', 'allow_squash_merge': True, 'allow_merge_commit': True, 'allow_rebase_merge': True, 'allow_auto_merge': False, 'delete_branch_on_merge': False, 'allow_update_branch': False, 'use_squash_pr_title_as_default': False, 'squash_merge_commit_message': 'COMMIT_MESSAGES', 'squash_merge_commit_title': 'COMMIT_OR_PR_TITLE', 'merge_commit_message': 'PR_TITLE', 'merge_commit_title': 'MERGE_MESSAGE'}}, 'base': {'label': 'dolphin-emu:master', 'ref': 'master', 'sha': 'd3b2943807dd0073f7767947466dd73cccfef319', 'user': {'login': 'dolphin-emu', 'id': 5050316, 'node_id': 'MDEyOk9yZ2FuaXphdGlvbjUwNTAzMTY=', 'avatar_url': 'https://avatars.githubusercontent.com/u/5050316?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/dolphin-emu', 'html_url': 'https://github.com/dolphin-emu', 'followers_url': 'https://api.github.com/users/dolphin-emu/followers', 'following_url': 'https://api.github.com/users/dolphin-emu/following{/other_user}', 'gists_url': 'https://api.github.com/users/dolphin-emu/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/dolphin-emu/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/dolphin-emu/subscriptions', 'organizations_url': 'https://api.github.com/users/dolphin-emu/orgs', 'repos_url': 'https://api.github.com/users/dolphin-emu/repos', 'events_url': 'https://api.github.com/users/dolphin-emu/events{/privacy}', 'received_events_url': 'https://api.github.com/users/dolphin-emu/received_events', 'type': 'Organization', 'user_view_type': 'public', 'site_admin': False}, 'repo': {'id': 11577304, 'node_id': 'MDEwOlJlcG9zaXRvcnkxMTU3NzMwNA==', 'name': 'dolphin', 'full_name': 'dolphin-emu/dolphin', 'private': False, 'owner': {'login': 'dolphin-emu', 'id': 5050316, 'node_id': 'MDEyOk9yZ2FuaXphdGlvbjUwNTAzMTY=', 'avatar_url': 'https://avatars.githubusercontent.com/u/5050316?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/dolphin-emu', 'html_url': 'https://github.com/dolphin-emu', 'followers_url': 'https://api.github.com/users/dolphin-emu/followers', 'following_url': 'https://api.github.com/users/dolphin-emu/following{/other_user}', 'gists_url': 'https://api.github.com/users/dolphin-emu/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/dolphin-emu/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/dolphin-emu/subscriptions', 'organizations_url': 'https://api.github.com/users/dolphin-emu/orgs', 'repos_url': 'https://api.github.com/users/dolphin-emu/repos', 'events_url': 'https://api.github.com/users/dolphin-emu/events{/privacy}', 'received_events_url': 'https://api.github.com/users/dolphin-emu/received_events', 'type': 'Organization', 'user_view_type': 'public', 'site_admin': False}, 'html_url': 'https://github.com/dolphin-emu/dolphin', 'description': 'Dolphin is a GameCube / Wii emulator, allowing you to play games for these two platforms on PC with improvements.', 'fork': False, 'url': 'https://api.github.com/repos/dolphin-emu/dolphin', 'forks_url': 'https://api.github.com/repos/dolphin-emu/dolphin/forks', 'keys_url': 'https://api.github.com/repos/dolphin-emu/dolphin/keys{/key_id}', 'collaborators_url': 'https://api.github.com/repos/dolphin-emu/dolphin/collaborators{/collaborator}', 'teams_url': 'https://api.github.com/repos/dolphin-emu/dolphin/teams', 'hooks_url': 'https://api.github.com/repos/dolphin-emu/dolphin/hooks', 'issue_events_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/events{/number}', 'events_url': 'https://api.github.com/repos/dolphin-emu/dolphin/events', 'assignees_url': 'https://api.github.com/repos/dolphin-emu/dolphin/assignees{/user}', 'branches_url': 'https://api.github.com/repos/dolphin-emu/dolphin/branches{/branch}', 'tags_url': 'https://api.github.com/repos/dolphin-emu/dolphin/tags', 'blobs_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/blobs{/sha}', 'git_tags_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/tags{/sha}', 'git_refs_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/refs{/sha}', 'trees_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/trees{/sha}', 'statuses_url': 'https://api.github.com/repos/dolphin-emu/dolphin/statuses/{sha}', 'languages_url': 'https://api.github.com/repos/dolphin-emu/dolphin/languages', 'stargazers_url': 'https://api.github.com/repos/dolphin-emu/dolphin/stargazers', 'contributors_url': 'https://api.github.com/repos/dolphin-emu/dolphin/contributors', 'subscribers_url': 'https://api.github.com/repos/dolphin-emu/dolphin/subscribers', 'subscription_url': 'https://api.github.com/repos/dolphin-emu/dolphin/subscription', 'commits_url': 'https://api.github.com/repos/dolphin-emu/dolphin/commits{/sha}', 'git_commits_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/commits{/sha}', 'comments_url': 'https://api.github.com/repos/dolphin-emu/dolphin/comments{/number}', 'issue_comment_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/comments{/number}', 'contents_url': 'https://api.github.com/repos/dolphin-emu/dolphin/contents/{+path}', 'compare_url': 'https://api.github.com/repos/dolphin-emu/dolphin/compare/{base}...{head}', 'merges_url': 'https://api.github.com/repos/dolphin-emu/dolphin/merges', 'archive_url': 'https://api.github.com/repos/dolphin-emu/dolphin/{archive_format}{/ref}', 'downloads_url': 'https://api.github.com/repos/dolphin-emu/dolphin/downloads', 'issues_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues{/number}', 'pulls_url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls{/number}', 'milestones_url': 'https://api.github.com/repos/dolphin-emu/dolphin/milestones{/number}', 'notifications_url': 'https://api.github.com/repos/dolphin-emu/dolphin/notifications{?since,all,participating}', 'labels_url': 'https://api.github.com/repos/dolphin-emu/dolphin/labels{/name}', 'releases_url': 'https://api.github.com/repos/dolphin-emu/dolphin/releases{/id}', 'deployments_url': 'https://api.github.com/repos/dolphin-emu/dolphin/deployments', 'created_at': '2013-07-22T09:07:57Z', 'updated_at': '2026-07-18T23:13:54Z', 'pushed_at': '2026-07-18T10:34:54Z', 'git_url': 'git://github.com/dolphin-emu/dolphin.git', 'ssh_url': 'git@github.com:dolphin-emu/dolphin.git', 'clone_url': 'https://github.com/dolphin-emu/dolphin.git', 'svn_url': 'https://github.com/dolphin-emu/dolphin', 'homepage': 'https://dolphin-emu.org', 'size': 558448, 'stargazers_count': 15273, 'watchers_count': 15273, 'language': 'C++', 'has_issues': False, 'has_projects': False, 'has_downloads': True, 'has_wiki': True, 'has_pages': False, 'has_discussions': False, 'forks_count': 3162, 'mirror_url': None, 'archived': False, 'disabled': False, 'open_issues_count': 446, 'license': {'key': 'other', 'name': 'Other', 'spdx_id': 'NOASSERTION', 'url': None, 'node_id': 'MDc6TGljZW5zZTA='}, 'allow_forking': True, 'is_template': False, 'web_commit_signoff_required': False, 'has_pull_requests': True, 'pull_request_creation_policy': 'all', 'topics': ['cpp', 'emulation', 'emulator', 'gamecube', 'wii'], 'visibility': 'public', 'forks': 3162, 'open_issues': 446, 'watchers': 15273, 'default_branch': 'master', 'allow_squash_merge': False, 'allow_merge_commit': True, 'allow_rebase_merge': False, 'allow_auto_merge': False, 'delete_branch_on_merge': False, 'allow_update_branch': False, 'use_squash_pr_title_as_default': False, 'squash_merge_commit_message': 'COMMIT_MESSAGES', 'squash_merge_commit_title': 'COMMIT_OR_PR_TITLE', 'merge_commit_message': 'PR_TITLE', 'merge_commit_title': 'MERGE_MESSAGE'}}, '_links': {'self': {'href': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/14731'}, 'html': {'href': 'https://github.com/dolphin-emu/dolphin/pull/14731'}, 'issue': {'href': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/14731'}, 'comments': {'href': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/14731/comments'}, 'review_comments': {'href': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/14731/comments'}, 'review_comment': {'href': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/comments{/number}'}, 'commits': {'href': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/14731/commits'}, 'statuses': {'href': 'https://api.github.com/repos/dolphin-emu/dolphin/statuses/24b41d58df2315831b74f76b95417f2739d02f9d'}}, 'author_association': 'NONE', 'auto_merge': None, 'assignee': None, 'active_lock_reason': None}, 'repository': {'id': 11577304, 'node_id': 'MDEwOlJlcG9zaXRvcnkxMTU3NzMwNA==', 'name': 'dolphin', 'full_name': 'dolphin-emu/dolphin', 'private': False, 'owner': {'login': 'dolphin-emu', 'id': 5050316, 'node_id': 'MDEyOk9yZ2FuaXphdGlvbjUwNTAzMTY=', 'avatar_url': 'https://avatars.githubusercontent.com/u/5050316?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/dolphin-emu', 'html_url': 'https://github.com/dolphin-emu', 'followers_url': 'https://api.github.com/users/dolphin-emu/followers', 'following_url': 'https://api.github.com/users/dolphin-emu/following{/other_user}', 'gists_url': 'https://api.github.com/users/dolphin-emu/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/dolphin-emu/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/dolphin-emu/subscriptions', 'organizations_url': 'https://api.github.com/users/dolphin-emu/orgs', 'repos_url': 'https://api.github.com/users/dolphin-emu/repos', 'events_url': 'https://api.github.com/users/dolphin-emu/events{/privacy}', 'received_events_url': 'https://api.github.com/users/dolphin-emu/received_events', 'type': 'Organization', 'user_view_type': 'public', 'site_admin': False}, 'html_url': 'https://github.com/dolphin-emu/dolphin', 'description': 'Dolphin is a GameCube / Wii emulator, allowing you to play games for these two platforms on PC with improvements.', 'fork': False, 'url': 'https://api.github.com/repos/dolphin-emu/dolphin', 'forks_url': 'https://api.github.com/repos/dolphin-emu/dolphin/forks', 'keys_url': 'https://api.github.com/repos/dolphin-emu/dolphin/keys{/key_id}', 'collaborators_url': 'https://api.github.com/repos/dolphin-emu/dolphin/collaborators{/collaborator}', 'teams_url': 'https://api.github.com/repos/dolphin-emu/dolphin/teams', 'hooks_url': 'https://api.github.com/repos/dolphin-emu/dolphin/hooks', 'issue_events_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/events{/number}', 'events_url': 'https://api.github.com/repos/dolphin-emu/dolphin/events', 'assignees_url': 'https://api.github.com/repos/dolphin-emu/dolphin/assignees{/user}', 'branches_url': 'https://api.github.com/repos/dolphin-emu/dolphin/branches{/branch}', 'tags_url': 'https://api.github.com/repos/dolphin-emu/dolphin/tags', 'blobs_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/blobs{/sha}', 'git_tags_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/tags{/sha}', 'git_refs_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/refs{/sha}', 'trees_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/trees{/sha}', 'statuses_url': 'https://api.github.com/repos/dolphin-emu/dolphin/statuses/{sha}', 'languages_url': 'https://api.github.com/repos/dolphin-emu/dolphin/languages', 'stargazers_url': 'https://api.github.com/repos/dolphin-emu/dolphin/stargazers', 'contributors_url': 'https://api.github.com/repos/dolphin-emu/dolphin/contributors', 'subscribers_url': 'https://api.github.com/repos/dolphin-emu/dolphin/subscribers', 'subscription_url': 'https://api.github.com/repos/dolphin-emu/dolphin/subscription', 'commits_url': 'https://api.github.com/repos/dolphin-emu/dolphin/commits{/sha}', 'git_commits_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/commits{/sha}', 'comments_url': 'https://api.github.com/repos/dolphin-emu/dolphin/comments{/number}', 'issue_comment_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/comments{/number}', 'contents_url': 'https://api.github.com/repos/dolphin-emu/dolphin/contents/{+path}', 'compare_url': 'https://api.github.com/repos/dolphin-emu/dolphin/compare/{base}...{head}', 'merges_url': 'https://api.github.com/repos/dolphin-emu/dolphin/merges', 'archive_url': 'https://api.github.com/repos/dolphin-emu/dolphin/{archive_format}{/ref}', 'downloads_url': 'https://api.github.com/repos/dolphin-emu/dolphin/downloads', 'issues_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues{/number}', 'pulls_url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls{/number}', 'milestones_url': 'https://api.github.com/repos/dolphin-emu/dolphin/milestones{/number}', 'notifications_url': 'https://api.github.com/repos/dolphin-emu/dolphin/notifications{?since,all,participating}', 'labels_url': 'https://api.github.com/repos/dolphin-emu/dolphin/labels{/name}', 'releases_url': 'https://api.github.com/repos/dolphin-emu/dolphin/releases{/id}', 'deployments_url': 'https://api.github.com/repos/dolphin-emu/dolphin/deployments', 'created_at': '2013-07-22T09:07:57Z', 'updated_at': '2026-07-18T23:13:54Z', 'pushed_at': '2026-07-18T10:34:54Z', 'git_url': 'git://github.com/dolphin-emu/dolphin.git', 'ssh_url': 'git@github.com:dolphin-emu/dolphin.git', 'clone_url': 'https://github.com/dolphin-emu/dolphin.git', 'svn_url': 'https://github.com/dolphin-emu/dolphin', 'homepage': 'https://dolphin-emu.org', 'size': 558448, 'stargazers_count': 15273, 'watchers_count': 15273, 'language': 'C++', 'has_issues': False, 'has_projects': False, 'has_downloads': True, 'has_wiki': True, 'has_pages': False, 'has_discussions': False, 'forks_count': 3162, 'mirror_url': None, 'archived': False, 'disabled': False, 'open_issues_count': 446, 'license': {'key': 'other', 'name': 'Other', 'spdx_id': 'NOASSERTION', 'url': None, 'node_id': 'MDc6TGljZW5zZTA='}, 'allow_forking': True, 'is_template': False, 'web_commit_signoff_required': False, 'has_pull_requests': True, 'pull_request_creation_policy': 'all', 'topics': ['cpp', 'emulation', 'emulator', 'gamecube', 'wii'], 'visibility': 'public', 'forks': 3162, 'open_issues': 446, 'watchers': 15273, 'default_branch': 'master', 'custom_properties': {}}, 'organization': {'login': 'dolphin-emu', 'id': 5050316, 'node_id': 'MDEyOk9yZ2FuaXphdGlvbjUwNTAzMTY=', 'url': 'https://api.github.com/orgs/dolphin-emu', 'repos_url': 'https://api.github.com/orgs/dolphin-emu/repos', 'events_url': 'https://api.github.com/orgs/dolphin-emu/events', 'hooks_url': 'https://api.github.com/orgs/dolphin-emu/hooks', 'issues_url': 'https://api.github.com/orgs/dolphin-emu/issues', 'members_url': 'https://api.github.com/orgs/dolphin-emu/members{/member}', 'public_members_url': 'https://api.github.com/orgs/dolphin-emu/public_members{/member}', 'avatar_url': 'https://avatars.githubusercontent.com/u/5050316?v=4', 'description': ''}, 'sender': {'login': 'thethiny', 'id': 6018214, 'node_id': 'MDQ6VXNlcjYwMTgyMTQ=', 'avatar_url': 'https://avatars.githubusercontent.com/u/6018214?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/thethiny', 'html_url': 'https://github.com/thethiny', 'followers_url': 'https://api.github.com/users/thethiny/followers', 'following_url': 'https://api.github.com/users/thethiny/following{/other_user}', 'gists_url': 'https://api.github.com/users/thethiny/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/thethiny/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/thethiny/subscriptions', 'organizations_url': 'https://api.github.com/users/thethiny/orgs', 'repos_url': 'https://api.github.com/users/thethiny/repos', 'events_url': 'https://api.github.com/users/thethiny/events{/privacy}', 'received_events_url': 'https://api.github.com/users/thethiny/received_events', 'type': 'User', 'user_view_type': 'public', 'site_admin': False}, 'installation': {'id': 35437981, 'node_id': 'MDIzOkludGVncmF0aW9uSW5zdGFsbGF0aW9uMzU0Mzc5ODE='}}, 'type': 'raw_gh_hook'}
2026-07-18T23:37:37.379700	{'source': 'ghhookparser', 'repo': 'dolphin-emu/dolphin', 'author': 'thethiny', 'action': 'submitted', 'pr_id': 14731, 'pr_title': 'Convert To WBFS Support', 'state': 'commented', 'url': 'https://github.com/dolphin-emu/dolphin/pull/14731#pullrequestreview-4729501733', 'comments': [{'id': 3609419546, 'node_id': 'PRRC_kwDOALCn2M7XI18a', 'url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/comments/3609419546', 'pull_request_review_id': 4729501733, 'diff_hunk': '@@ -186,7 +380,304 @@ std::unique_ptr<WbfsFileReader> WbfsFileReader::Create(File::DirectIOFile file,\n   if (!reader->IsGood())\n     reader.reset();\n \n+  if (reader && reader->m_has_nkit_header)\n+    reader->ReadPartitionInfo();\n+\n   return reader;\n }\n \n+// Converts any disc image to WBFS with an NKit v2 header for lossless round-trips.\n+// Strips disc-level junk and partition-level junk (encrypted sectors whose decrypted\n+// content is zero or LFG padding), records a junk bitmap for reconstruction.\n+// See: https://github.com/dolphin-emu/dolphin/pull/14731\n+bool ConvertToWBFS(BlobReader* infile, const std::string& infile_path,\n+                   const std::string& outfile_path, const CompressCB& callback)\n+{\n+  ASSERT(infile->GetDataSizeType() == DataSizeType::Accurate ||\n+         infile->GetDataSizeType() == DataSizeType::UpperBound);\n+\n+  File::DirectIOFile outfile(outfile_path, File::AccessMode::Write);\n+  if (!outfile.IsOpen())\n+  {\n+    PanicAlertFmtT(\n+        "Failed to open the output file \\"{0}\\".\\n"\n+        "Check that you have permissions to write the target folder and that the media can "\n+        "be written.",\n+        outfile_path);\n+    return false;\n+  }\n+\n+  const u64 disc_size = infile->GetDataSize();\n+\n+  // These match the values used by standard WBFS tools (wwt, WBFS Manager)\n+  static constexpr u8 hd_sector_shift = 9;\n+  static constexpr u8 wbfs_sector_shift = 21;\n+  static constexpr u64 hd_sector_size = 1ull << hd_sector_shift;\n+  static constexpr u64 wbfs_sector_size = 1ull << wbfs_sector_shift;\n+\n+  const u64 blocks_per_disc = (disc_size + wbfs_sector_size - 1) / wbfs_sector_size;\n+  const u64 disc_info_size =\n+      Common::AlignUp(WII_DISC_HEADER_SIZE + blocks_per_disc * sizeof(u16), hd_sector_size);\n+\n+  // Read disc header (first 256 bytes contain disc_id, disc_num, title, etc.)\n+  std::vector<u8> disc_header(WII_DISC_HEADER_SIZE, 0);\n+  if (!infile->Read(0, WII_DISC_HEADER_SIZE, disc_header.data()))\n+  {\n+    PanicAlertFmtT("Failed to read from the input file \\"{0}\\".", infile_path);\n+    return false;\n+  }\n+\n+  // Use Volume for partition info and decrypted reads\n+  struct PartitionInfo\n+  {\n+    u64 data_offset;\n+    u64 data_size;\n+    Partition partition;\n+  };\n+  std::vector<PartitionInfo> partitions;\n+\n+  std::unique_ptr<VolumeDisc> volume = CreateDisc(infile_path);\n+  if (volume)\n+  {\n+    for (const Partition& partition : volume->GetPartitions())\n+    {\n+      const std::optional<u64> data_offset =\n+          volume->ReadSwappedAndShifted(partition.offset + 0x2B8, PARTITION_NONE);\n+      const std::optional<u64> data_size =\n+          volume->ReadSwappedAndShifted(partition.offset + 0x2BC, PARTITION_NONE);\n+      if (!data_offset || !data_size)\n+        continue;\n+\n+      PartitionInfo info;\n+      info.data_offset = partition.offset + *data_offset;\n+      info.data_size = *data_size;\n+      info.partition = partition;\n+      partitions.push_back(info);\n+    }\n+  }\n+\n+  // NKit v2 gap type bitmap: 1 bit per block, MSB-first, always sized for dual-layer\n+  const u64 gap_type_blocks = (DL_DVD_SIZE + wbfs_sector_size - 1) / wbfs_sector_size;\n+  const u64 gap_type_bytes = (gap_type_blocks + 7) / 8;\n+  std::vector<u8> gap_type(gap_type_bytes, 0);\n+\n+  // Compute data_start up front so we can write sectors during the scan\n+  const u64 data_start = Common::AlignUp(hd_sector_size + disc_info_size, wbfs_sector_size);\n+  const u16 wlba_base = static_cast<u16>(data_start / wbfs_sector_size);\n+\n+  // Single pass: scan, classify, hash, and write used sectors in one loop\n+  std::vector<u8> sector_buf(wbfs_sector_size, 0);\n+  std::vector<u16> wlba_table(blocks_per_disc, 0);\n+  u16 used_count = 0;\n+\n+  // NKit v2 stores four hash digests for verification\n+  auto sha1_ctx = Common::SHA1::CreateContext();\n+  u32 crc = Common::StartCRC32();\n+  mbedtls_md5_context md5_ctx{};\n+  mbedtls_md5_init(&md5_ctx);\n+  mbedtls_md5_starts_ret(&md5_ctx);\n+  XXH64_state_t* xxh_state = XXH64_createState();\n+  XXH64_reset(xxh_state, 0);\n+\n+  for (u64 i = 0; i < blocks_per_disc; i++)\n+  {\n+    if (i % 100 == 0)\n+    {\n+      const bool was_cancelled =\n+          !callback(Common::GetStringT("Converting"),\n+                    static_cast<float>(i) / static_cast<float>(blocks_per_disc));\n+      if (was_cancelled)\n+      {\n+        XXH64_freeState(xxh_state);\n+        mbedtls_md5_free(&md5_ctx);\n+        outfile.Close();\n+        File::Delete(outfile_path);\n+        return false;\n+      }\n+    }\n+\n+    const u64 offset = i * wbfs_sector_size;\n+    const size_t sz = static_cast<size_t>(std::min(wbfs_sector_size, disc_size - offset));\n+\n+    if (!infile->Read(offset, sz, sector_buf.data()))\n+    {\n+      PanicAlertFmtT("Failed to read from the input file \\"{0}\\".", infile_path);\n+      XXH64_freeState(xxh_state);\n+      mbedtls_md5_free(&md5_ctx);\n+      outfile.Close();\n+      File::Delete(outfile_path);\n+      return false;\n+    }\n+\n+    // Update all four hashes with the full disc data\n+    sha1_ctx->Update(sector_buf.data(), sz);\n+    crc = Common::UpdateCRC32(crc, sector_buf.data(), sz);\n+    mbedtls_md5_update_ret(&md5_ctx, sector_buf.data(), sz);\n+    XXH64_update(xxh_state, sector_buf.data(), sz);\n+\n+    // Find which partition (if any) this block belongs to\n+    const u32 start_sector = static_cast<u32>(offset / VolumeWii::BLOCK_TOTAL_SIZE);\n+    const u32 end_sector = static_cast<u32>((offset + sz) / VolumeWii::BLOCK_TOTAL_SIZE);\n+    const auto it = std::ranges::find_if(partitions, [&](const PartitionInfo& p) {\n+      const u32 p_start = static_cast<u32>(p.data_offset / VolumeWii::BLOCK_TOTAL_SIZE);\n+      const u32 p_end =\n+          static_cast<u32>((p.data_offset + p.data_size) / VolumeWii::BLOCK_TOTAL_SIZE);', 'path': 'Source/Core/DiscIO/WbfsBlob.cpp', 'position': 431, 'original_position': 431, 'commit_id': '24b41d58df2315831b74f76b95417f2739d02f9d', 'user': {'login': 'thethiny', 'id': 6018214, 'node_id': 'MDQ6VXNlcjYwMTgyMTQ=', 'avatar_url': 'https://avatars.githubusercontent.com/u/6018214?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/thethiny', 'html_url': 'https://github.com/thethiny', 'followers_url': 'https://api.github.com/users/thethiny/followers', 'following_url': 'https://api.github.com/users/thethiny/following{/other_user}', 'gists_url': 'https://api.github.com/users/thethiny/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/thethiny/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/thethiny/subscriptions', 'organizations_url': 'https://api.github.com/users/thethiny/orgs', 'repos_url': 'https://api.github.com/users/thethiny/repos', 'events_url': 'https://api.github.com/users/thethiny/events{/privacy}', 'received_events_url': 'https://api.github.com/users/thethiny/received_events', 'type': 'User', 'user_view_type': 'public', 'site_admin': False}, 'body': 'this is an oversight on my end due to iterative coding. Noted', 'created_at': '2026-07-18T23:37:35Z', 'updated_at': '2026-07-18T23:37:35Z', 'html_url': 'https://github.com/dolphin-emu/dolphin/pull/14731#discussion_r3609419546', 'pull_request_url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/14731', 'author_association': 'NONE', '_links': {'self': {'href': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/comments/3609419546'}, 'html': {'href': 'https://github.com/dolphin-emu/dolphin/pull/14731#discussion_r3609419546'}, 'pull_request': {'href': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/14731'}}, 'original_commit_id': '24b41d58df2315831b74f76b95417f2739d02f9d', 'reactions': {'url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/comments/3609419546/reactions', 'total_count': 0, '+1': 0, '-1': 0, 'laugh': 0, 'hooray': 0, 'confused': 0, 'heart': 0, 'rocket': 0, 'eyes': 0}, 'in_reply_to_id': 3609363364}], 'type': 'gh_pull_request_review'}
2026-07-18T23:36:12.676971	{'source': 'notifications', 'msg': '[\x1f\x0313dolphin-emu/dolphin\x03\x1f] \x0303t\ufeffhethiny\x03 commented on #14731 24b41d: \x1f\x0302https://dolp.in/pr14731#discussion_r3609417157\x03\x1f', 'type': 'notification'}
2026-07-18T23:36:12.676814	{'source': 'webserver', 'gh_type': 'pull_request_review_comment', 'raw': {'action': 'created', 'comment': {'url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/comments/3609417157', 'pull_request_review_id': 4729499717, 'id': 3609417157, 'node_id': 'PRRC_kwDOALCn2M7XI1XF', 'diff_hunk': '@@ -119,22 +144,191 @@ bool WbfsFileReader::ReadHeader()\n   return m_header.disc_table[0] != 0;\n }\n \n+bool WbfsFileReader::ReadNKitHeader()\n+{\n+  const u64 gap_type_blocks = (DL_DVD_SIZE + m_wbfs_sector_size - 1) / m_wbfs_sector_size;\n+  m_nkit_info = NKit::ReadHeaderFromFile(m_files[0].file, NKit::HEADER_OFFSET, gap_type_blocks);\n+  if (!m_nkit_info.valid)\n+    return false;\n+\n+  m_has_nkit_header = true;\n+  return true;\n+}\n+\n+bool WbfsFileReader::IsBlockStored(u64 block_index) const\n+{\n+  return block_index < m_blocks_per_disc && m_wlba_table[block_index] != 0;\n+}\n+\n+bool WbfsFileReader::IsGapJunk(u64 block_index) const\n+{\n+  return NKit::IsGapJunk(m_nkit_info.gap_type, block_index);\n+}\n+\n+void WbfsFileReader::GenerateJunkData(u64 disc_offset, u64 size, u8* out) const\n+{\n+  LaggedFibonacciGenerator::FillJunkData(out, static_cast<size_t>(size), disc_offset, m_disc_id,\n+                                         m_disc_num);\n+}\n+\n+void WbfsFileReader::ReadPartitionInfo()\n+{\n+  std::unique_ptr<VolumeDisc> volume = CreateDisc(CopyReader());\n+  if (!volume)\n+    return;\n+\n+  for (const Partition& partition : volume->GetPartitions())\n+  {\n+    const auto& ticket = volume->GetTicket(partition);\n+    const std::array<u8, 16> title_key = ticket.GetTitleKey();\n+\n+    u8 data_info[8];\n+    if (!Read(partition.offset + 0x2B8, 8, data_info))\n+      continue;\n+\n+    PartitionEntry entry;\n+    entry.data_offset = partition.offset + (static_cast<u64>(Common::swap32(data_info)) << 2);\n+    entry.data_size = static_cast<u64>(Common::swap32(data_info + 4)) << 2;\n+    entry.key = title_key;\n+    m_partitions.push_back(entry);\n+  }\n+}\n+\n+const WbfsFileReader::PartitionEntry* WbfsFileReader::FindPartition(u64 disc_offset) const\n+{\n+  for (const auto& p : m_partitions)\n+  {\n+    if (disc_offset >= p.data_offset && disc_offset < p.data_offset + p.data_size)\n+      return &p;\n+  }\n+  return nullptr;\n+}\n+\n+const WbfsFileReader::PartitionEntry*\n+WbfsFileReader::FindPartitionByDataOffset(u64 partition_data_offset) const\n+{\n+  for (const auto& p : m_partitions)\n+  {\n+    if (p.data_offset == partition_data_offset)\n+      return &p;\n+  }\n+  return nullptr;\n+}\n+\n+bool WbfsFileReader::SupportsReadWiiDecrypted(u64 offset, u64 size, u64 partition_data_offset) const\n+{\n+  if (!m_has_nkit_header)\n+    return false;\n+\n+  const u64 block_in_partition = offset / VolumeWii::BLOCK_DATA_SIZE;\n+  const u64 disc_offset = partition_data_offset + block_in_partition * VolumeWii::BLOCK_TOTAL_SIZE;\n+  const u64 wbfs_block = disc_offset >> m_header.wbfs_sector_shift;\n+\n+  return wbfs_block < m_blocks_per_disc && !IsBlockStored(wbfs_block);\n+}\n+\n+bool WbfsFileReader::ReadWiiDecrypted(u64 offset, u64 size, u8* out_ptr, u64 partition_data_offset)\n+{\n+  const PartitionEntry* pe = FindPartitionByDataOffset(partition_data_offset);\n+  if (!pe)\n+    return false;\n+\n+  auto aes_ctx = Common::AES::CreateContextDecrypt(pe->key.data());\n+  std::vector<u8> encrypted(VolumeWii::BLOCK_TOTAL_SIZE);\n+  std::vector<u8> decrypted(VolumeWii::BLOCK_DATA_SIZE);\n+\n+  while (size > 0)\n+  {\n+    const u64 block_in_partition = offset / VolumeWii::BLOCK_DATA_SIZE;\n+    const u64 offset_in_block = offset % VolumeWii::BLOCK_DATA_SIZE;\n+    const u64 bytes_in_block = VolumeWii::BLOCK_DATA_SIZE - offset_in_block;\n+    const size_t read_size = static_cast<size_t>(std::min(bytes_in_block, size));\n+\n+    const u64 disc_offset =\n+        partition_data_offset + block_in_partition * VolumeWii::BLOCK_TOTAL_SIZE;\n+    const u64 wbfs_block = disc_offset >> m_header.wbfs_sector_shift;\n+\n+    if (IsBlockStored(wbfs_block))\n+    {\n+      u64 available;\n+      auto& file = SeekToCluster(disc_offset, &available);\n+      if (available < VolumeWii::BLOCK_TOTAL_SIZE ||\n+          !file.Read(encrypted.data(), VolumeWii::BLOCK_TOTAL_SIZE))\n+        return false;\n+      VolumeWii::DecryptBlockData(encrypted.data(), decrypted.data(), aes_ctx.get());\n+      std::memcpy(out_ptr, decrypted.data() + offset_in_block, read_size);\n+    }', 'path': 'Source/Core/DiscIO/WbfsBlob.cpp', 'commit_id': '24b41d58df2315831b74f76b95417f2739d02f9d', 'original_commit_id': '24b41d58df2315831b74f76b95417f2739d02f9d', 'user': {'login': 'thethiny', 'id': 6018214, 'node_id': 'MDQ6VXNlcjYwMTgyMTQ=', 'avatar_url': 'https://avatars.githubusercontent.com/u/6018214?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/thethiny', 'html_url': 'https://github.com/thethiny', 'followers_url': 'https://api.github.com/users/thethiny/followers', 'following_url': 'https://api.github.com/users/thethiny/following{/other_user}', 'gists_url': 'https://api.github.com/users/thethiny/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/thethiny/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/thethiny/subscriptions', 'organizations_url': 'https://api.github.com/users/thethiny/orgs', 'repos_url': 'https://api.github.com/users/thethiny/repos', 'events_url': 'https://api.github.com/users/thethiny/events{/privacy}', 'received_events_url': 'https://api.github.com/users/thethiny/received_events', 'type': 'User', 'user_view_type': 'public', 'site_admin': False}, 'body': 'This needs an investigation, since EncryptGroup processes about 64 sectors and therefore the sectors could be a mix of stored and non-stored blocks. It is possible that this path will never hit but I cannot confirm that since I did not test it out. I will do so and report back with either a fix or a result.', 'created_at': '2026-07-18T23:36:11Z', 'updated_at': '2026-07-18T23:36:11Z', 'html_url': 'https://github.com/dolphin-emu/dolphin/pull/14731#discussion_r3609417157', 'pull_request_url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/14731', '_links': {'self': {'href': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/comments/3609417157'}, 'html': {'href': 'https://github.com/dolphin-emu/dolphin/pull/14731#discussion_r3609417157'}, 'pull_request': {'href': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/14731'}}, 'reactions': {'url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/comments/3609417157/reactions', 'total_count': 0, '+1': 0, '-1': 0, 'laugh': 0, 'hooray': 0, 'confused': 0, 'heart': 0, 'rocket': 0, 'eyes': 0}, 'start_line': 251, 'original_start_line': 251, 'start_side': 'RIGHT', 'line': 260, 'original_line': 260, 'side': 'RIGHT', 'in_reply_to_id': 3609277919, 'author_association': 'NONE', 'original_position': 204, 'position': 204, 'subject_type': 'line'}, 'pull_request': {'url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/14731', 'id': 4056977334, 'node_id': 'PR_kwDOALCn2M7x0I-2', 'html_url': 'https://github.com/dolphin-emu/dolphin/pull/14731', 'diff_url': 'https://github.com/dolphin-emu/dolphin/pull/14731.diff', 'patch_url': 'https://github.com/dolphin-emu/dolphin/pull/14731.patch', 'issue_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/14731', 'number': 14731, 'state': 'open', 'locked': False, 'title': 'Convert To WBFS Support', 'user': {'login': 'thethiny', 'id': 6018214, 'node_id': 'MDQ6VXNlcjYwMTgyMTQ=', 'avatar_url': 'https://avatars.githubusercontent.com/u/6018214?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/thethiny', 'html_url': 'https://github.com/thethiny', 'followers_url': 'https://api.github.com/users/thethiny/followers', 'following_url': 'https://api.github.com/users/thethiny/following{/other_user}', 'gists_url': 'https://api.github.com/users/thethiny/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/thethiny/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/thethiny/subscriptions', 'organizations_url': 'https://api.github.com/users/thethiny/orgs', 'repos_url': 'https://api.github.com/users/thethiny/repos', 'events_url': 'https://api.github.com/users/thethiny/events{/privacy}', 'received_events_url': 'https://api.github.com/users/thethiny/received_events', 'type': 'User', 'user_view_type': 'public', 'site_admin': False}, 'body': "This PR introduces Conversion **to** WBFS support. WBFS is the format that is used by USB Loaders on a real Wii device.\r\n\r\n## Design decisions & hardcoded values\r\nThe writer uses fixed sector sizes that match what [libwbfs (the reference implementation by kwiirk)](https://github.com/kwiirk/wbfs/blob/master/libwbfs/libwbfs.c#L128-L134) computes for a standard single-layer Wii disc. These 2 hardcodes are stable and work correctly across all my testings.\r\n- HD sector shift: 9 (512 bytes)\r\n- WBFS sector shift: 21 (2 MiB)\r\nThese are not configurable via the UI. All existing WBFS tools use these values, and since the aim is to support USB Loaders then this has been tested and it is working on a real Wii.\r\n\r\nConverting from WBFS is not enabled. The existing `WbfsFileReader` reports `DataSizeType::UpperBound`, and `ShouldAllowConversion()` requires `Accurate`. I am able to support this but since it was hardcoded by the Dolphin team I thought a discussion is warranted.\r\n\r\n## Testing\r\n- Verified with DolphinTool header and DolphinTool verify\r\n- Verified with wit FILETYPE and wit DUMP (Wiimm's ISO Tools recognizes valid WBFS structure, partitions, encryption)\r\n- Tested ISO to WBFS and RVZ to WBFS conversions\r\n- Output file sizes match Wii Backup Manager when scrubbing is enabled (~0.1% difference), works when scrubbing is disabled.\r\n- Output WBFS files play correctly in Dolphin\r\n- Output WBFS files play correctly on a real Wii using USB Loader GX e25c4f3\r\n", 'created_at': '2026-07-15T01:16:25Z', 'updated_at': '2026-07-18T23:33:13Z', 'closed_at': None, 'merged_at': None, 'merge_commit_sha': '228f93416dd80eb09da834ad7852c8eaa4d9212b', 'assignees': [], 'requested_reviewers': [], 'requested_teams': [], 'labels': [], 'milestone': None, 'draft': False, 'commits_url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/14731/commits', 'review_comments_url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/14731/comments', 'review_comment_url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/comments{/number}', 'comments_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/14731/comments', 'statuses_url': 'https://api.github.com/repos/dolphin-emu/dolphin/statuses/24b41d58df2315831b74f76b95417f2739d02f9d', 'head': {'label': 'thethiny:wbfs-conversion', 'ref': 'wbfs-conversion', 'sha': '24b41d58df2315831b74f76b95417f2739d02f9d', 'user': {'login': 'thethiny', 'id': 6018214, 'node_id': 'MDQ6VXNlcjYwMTgyMTQ=', 'avatar_url': 'https://avatars.githubusercontent.com/u/6018214?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/thethiny', 'html_url': 'https://github.com/thethiny', 'followers_url': 'https://api.github.com/users/thethiny/followers', 'following_url': 'https://api.github.com/users/thethiny/following{/other_user}', 'gists_url': 'https://api.github.com/users/thethiny/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/thethiny/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/thethiny/subscriptions', 'organizations_url': 'https://api.github.com/users/thethiny/orgs', 'repos_url': 'https://api.github.com/users/thethiny/repos', 'events_url': 'https://api.github.com/users/thethiny/events{/privacy}', 'received_events_url': 'https://api.github.com/users/thethiny/received_events', 'type': 'User', 'user_view_type': 'public', 'site_admin': False}, 'repo': {'id': 1298654395, 'node_id': 'R_kgDOTWfkuw', 'name': 'dolphin', 'full_name': 'thethiny/dolphin', 'private': False, 'owner': {'login': 'thethiny', 'id': 6018214, 'node_id': 'MDQ6VXNlcjYwMTgyMTQ=', 'avatar_url': 'https://avatars.githubusercontent.com/u/6018214?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/thethiny', 'html_url': 'https://github.com/thethiny', 'followers_url': 'https://api.github.com/users/thethiny/followers', 'following_url': 'https://api.github.com/users/thethiny/following{/other_user}', 'gists_url': 'https://api.github.com/users/thethiny/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/thethiny/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/thethiny/subscriptions', 'organizations_url': 'https://api.github.com/users/thethiny/orgs', 'repos_url': 'https://api.github.com/users/thethiny/repos', 'events_url': 'https://api.github.com/users/thethiny/events{/privacy}', 'received_events_url': 'https://api.github.com/users/thethiny/received_events', 'type': 'User', 'user_view_type': 'public', 'site_admin': False}, 'html_url': 'https://github.com/thethiny/dolphin', 'description': 'Dolphin is a GameCube / Wii emulator, allowing you to play games for these two platforms on PC with improvements.', 'fork': True, 'url': 'https://api.github.com/repos/thethiny/dolphin', 'forks_url': 'https://api.github.com/repos/thethiny/dolphin/forks', 'keys_url': 'https://api.github.com/repos/thethiny/dolphin/keys{/key_id}', 'collaborators_url': 'https://api.github.com/repos/thethiny/dolphin/collaborators{/collaborator}', 'teams_url': 'https://api.github.com/repos/thethiny/dolphin/teams', 'hooks_url': 'https://api.github.com/repos/thethiny/dolphin/hooks', 'issue_events_url': 'https://api.github.com/repos/thethiny/dolphin/issues/events{/number}', 'events_url': 'https://api.github.com/repos/thethiny/dolphin/events', 'assignees_url': 'https://api.github.com/repos/thethiny/dolphin/assignees{/user}', 'branches_url': 'https://api.github.com/repos/thethiny/dolphin/branches{/branch}', 'tags_url': 'https://api.github.com/repos/thethiny/dolphin/tags', 'blobs_url': 'https://api.github.com/repos/thethiny/dolphin/git/blobs{/sha}', 'git_tags_url': 'https://api.github.com/repos/thethiny/dolphin/git/tags{/sha}', 'git_refs_url': 'https://api.github.com/repos/thethiny/dolphin/git/refs{/sha}', 'trees_url': 'https://api.github.com/repos/thethiny/dolphin/git/trees{/sha}', 'statuses_url': 'https://api.github.com/repos/thethiny/dolphin/statuses/{sha}', 'languages_url': 'https://api.github.com/repos/thethiny/dolphin/languages', 'stargazers_url': 'https://api.github.com/repos/thethiny/dolphin/stargazers', 'contributors_url': 'https://api.github.com/repos/thethiny/dolphin/contributors', 'subscribers_url': 'https://api.github.com/repos/thethiny/dolphin/subscribers', 'subscription_url': 'https://api.github.com/repos/thethiny/dolphin/subscription', 'commits_url': 'https://api.github.com/repos/thethiny/dolphin/commits{/sha}', 'git_commits_url': 'https://api.github.com/repos/thethiny/dolphin/git/commits{/sha}', 'comments_url': 'https://api.github.com/repos/thethiny/dolphin/comments{/number}', 'issue_comment_url': 'https://api.github.com/repos/thethiny/dolphin/issues/comments{/number}', 'contents_url': 'https://api.github.com/repos/thethiny/dolphin/contents/{+path}', 'compare_url': 'https://api.github.com/repos/thethiny/dolphin/compare/{base}...{head}', 'merges_url': 'https://api.github.com/repos/thethiny/dolphin/merges', 'archive_url': 'https://api.github.com/repos/thethiny/dolphin/{archive_format}{/ref}', 'downloads_url': 'https://api.github.com/repos/thethiny/dolphin/downloads', 'issues_url': 'https://api.github.com/repos/thethiny/dolphin/issues{/number}', 'pulls_url': 'https://api.github.com/repos/thethiny/dolphin/pulls{/number}', 'milestones_url': 'https://api.github.com/repos/thethiny/dolphin/milestones{/number}', 'notifications_url': 'https://api.github.com/repos/thethiny/dolphin/notifications{?since,all,participating}', 'labels_url': 'https://api.github.com/repos/thethiny/dolphin/labels{/name}', 'releases_url': 'https://api.github.com/repos/thethiny/dolphin/releases{/id}', 'deployments_url': 'https://api.github.com/repos/thethiny/dolphin/deployments', 'created_at': '2026-07-12T22:09:13Z', 'updated_at': '2026-07-12T22:09:13Z', 'pushed_at': '2026-07-18T20:35:03Z', 'git_url': 'git://github.com/thethiny/dolphin.git', 'ssh_url': 'git@github.com:thethiny/dolphin.git', 'clone_url': 'https://github.com/thethiny/dolphin.git', 'svn_url': 'https://github.com/thethiny/dolphin', 'homepage': 'https://dolphin-emu.org', 'size': 515471, 'stargazers_count': 0, 'watchers_count': 0, 'language': None, 'has_issues': False, 'has_projects': True, 'has_downloads': True, 'has_wiki': True, 'has_pages': False, 'has_discussions': False, 'forks_count': 0, 'mirror_url': None, 'archived': False, 'disabled': False, 'open_issues_count': 0, 'license': {'key': 'other', 'name': 'Other', 'spdx_id': 'NOASSERTION', 'url': None, 'node_id': 'MDc6TGljZW5zZTA='}, 'allow_forking': True, 'is_template': False, 'web_commit_signoff_required': False, 'has_pull_requests': True, 'pull_request_creation_policy': 'all', 'topics': [], 'visibility': 'public', 'forks': 0, 'open_issues': 0, 'watchers': 0, 'default_branch': 'master', 'allow_squash_merge': True, 'allow_merge_commit': True, 'allow_rebase_merge': True, 'allow_auto_merge': False, 'delete_branch_on_merge': False, 'allow_update_branch': False, 'use_squash_pr_title_as_default': False, 'squash_merge_commit_message': 'COMMIT_MESSAGES', 'squash_merge_commit_title': 'COMMIT_OR_PR_TITLE', 'merge_commit_message': 'PR_TITLE', 'merge_commit_title': 'MERGE_MESSAGE'}}, 'base': {'label': 'dolphin-emu:master', 'ref': 'master', 'sha': 'd3b2943807dd0073f7767947466dd73cccfef319', 'user': {'login': 'dolphin-emu', 'id': 5050316, 'node_id': 'MDEyOk9yZ2FuaXphdGlvbjUwNTAzMTY=', 'avatar_url': 'https://avatars.githubusercontent.com/u/5050316?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/dolphin-emu', 'html_url': 'https://github.com/dolphin-emu', 'followers_url': 'https://api.github.com/users/dolphin-emu/followers', 'following_url': 'https://api.github.com/users/dolphin-emu/following{/other_user}', 'gists_url': 'https://api.github.com/users/dolphin-emu/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/dolphin-emu/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/dolphin-emu/subscriptions', 'organizations_url': 'https://api.github.com/users/dolphin-emu/orgs', 'repos_url': 'https://api.github.com/users/dolphin-emu/repos', 'events_url': 'https://api.github.com/users/dolphin-emu/events{/privacy}', 'received_events_url': 'https://api.github.com/users/dolphin-emu/received_events', 'type': 'Organization', 'user_view_type': 'public', 'site_admin': False}, 'repo': {'id': 11577304, 'node_id': 'MDEwOlJlcG9zaXRvcnkxMTU3NzMwNA==', 'name': 'dolphin', 'full_name': 'dolphin-emu/dolphin', 'private': False, 'owner': {'login': 'dolphin-emu', 'id': 5050316, 'node_id': 'MDEyOk9yZ2FuaXphdGlvbjUwNTAzMTY=', 'avatar_url': 'https://avatars.githubusercontent.com/u/5050316?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/dolphin-emu', 'html_url': 'https://github.com/dolphin-emu', 'followers_url': 'https://api.github.com/users/dolphin-emu/followers', 'following_url': 'https://api.github.com/users/dolphin-emu/following{/other_user}', 'gists_url': 'https://api.github.com/users/dolphin-emu/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/dolphin-emu/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/dolphin-emu/subscriptions', 'organizations_url': 'https://api.github.com/users/dolphin-emu/orgs', 'repos_url': 'https://api.github.com/users/dolphin-emu/repos', 'events_url': 'https://api.github.com/users/dolphin-emu/events{/privacy}', 'received_events_url': 'https://api.github.com/users/dolphin-emu/received_events', 'type': 'Organization', 'user_view_type': 'public', 'site_admin': False}, 'html_url': 'https://github.com/dolphin-emu/dolphin', 'description': 'Dolphin is a GameCube / Wii emulator, allowing you to play games for these two platforms on PC with improvements.', 'fork': False, 'url': 'https://api.github.com/repos/dolphin-emu/dolphin', 'forks_url': 'https://api.github.com/repos/dolphin-emu/dolphin/forks', 'keys_url': 'https://api.github.com/repos/dolphin-emu/dolphin/keys{/key_id}', 'collaborators_url': 'https://api.github.com/repos/dolphin-emu/dolphin/collaborators{/collaborator}', 'teams_url': 'https://api.github.com/repos/dolphin-emu/dolphin/teams', 'hooks_url': 'https://api.github.com/repos/dolphin-emu/dolphin/hooks', 'issue_events_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/events{/number}', 'events_url': 'https://api.github.com/repos/dolphin-emu/dolphin/events', 'assignees_url': 'https://api.github.com/repos/dolphin-emu/dolphin/assignees{/user}', 'branches_url': 'https://api.github.com/repos/dolphin-emu/dolphin/branches{/branch}', 'tags_url': 'https://api.github.com/repos/dolphin-emu/dolphin/tags', 'blobs_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/blobs{/sha}', 'git_tags_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/tags{/sha}', 'git_refs_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/refs{/sha}', 'trees_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/trees{/sha}', 'statuses_url': 'https://api.github.com/repos/dolphin-emu/dolphin/statuses/{sha}', 'languages_url': 'https://api.github.com/repos/dolphin-emu/dolphin/languages', 'stargazers_url': 'https://api.github.com/repos/dolphin-emu/dolphin/stargazers', 'contributors_url': 'https://api.github.com/repos/dolphin-emu/dolphin/contributors', 'subscribers_url': 'https://api.github.com/repos/dolphin-emu/dolphin/subscribers', 'subscription_url': 'https://api.github.com/repos/dolphin-emu/dolphin/subscription', 'commits_url': 'https://api.github.com/repos/dolphin-emu/dolphin/commits{/sha}', 'git_commits_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/commits{/sha}', 'comments_url': 'https://api.github.com/repos/dolphin-emu/dolphin/comments{/number}', 'issue_comment_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/comments{/number}', 'contents_url': 'https://api.github.com/repos/dolphin-emu/dolphin/contents/{+path}', 'compare_url': 'https://api.github.com/repos/dolphin-emu/dolphin/compare/{base}...{head}', 'merges_url': 'https://api.github.com/repos/dolphin-emu/dolphin/merges', 'archive_url': 'https://api.github.com/repos/dolphin-emu/dolphin/{archive_format}{/ref}', 'downloads_url': 'https://api.github.com/repos/dolphin-emu/dolphin/downloads', 'issues_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues{/number}', 'pulls_url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls{/number}', 'milestones_url': 'https://api.github.com/repos/dolphin-emu/dolphin/milestones{/number}', 'notifications_url': 'https://api.github.com/repos/dolphin-emu/dolphin/notifications{?since,all,participating}', 'labels_url': 'https://api.github.com/repos/dolphin-emu/dolphin/labels{/name}', 'releases_url': 'https://api.github.com/repos/dolphin-emu/dolphin/releases{/id}', 'deployments_url': 'https://api.github.com/repos/dolphin-emu/dolphin/deployments', 'created_at': '2013-07-22T09:07:57Z', 'updated_at': '2026-07-18T23:13:54Z', 'pushed_at': '2026-07-18T10:34:54Z', 'git_url': 'git://github.com/dolphin-emu/dolphin.git', 'ssh_url': 'git@github.com:dolphin-emu/dolphin.git', 'clone_url': 'https://github.com/dolphin-emu/dolphin.git', 'svn_url': 'https://github.com/dolphin-emu/dolphin', 'homepage': 'https://dolphin-emu.org', 'size': 558448, 'stargazers_count': 15273, 'watchers_count': 15273, 'language': 'C++', 'has_issues': False, 'has_projects': False, 'has_downloads': True, 'has_wiki': True, 'has_pages': False, 'has_discussions': False, 'forks_count': 3162, 'mirror_url': None, 'archived': False, 'disabled': False, 'open_issues_count': 446, 'license': {'key': 'other', 'name': 'Other', 'spdx_id': 'NOASSERTION', 'url': None, 'node_id': 'MDc6TGljZW5zZTA='}, 'allow_forking': True, 'is_template': False, 'web_commit_signoff_required': False, 'has_pull_requests': True, 'pull_request_creation_policy': 'all', 'topics': ['cpp', 'emulation', 'emulator', 'gamecube', 'wii'], 'visibility': 'public', 'forks': 3162, 'open_issues': 446, 'watchers': 15273, 'default_branch': 'master', 'allow_squash_merge': False, 'allow_merge_commit': True, 'allow_rebase_merge': False, 'allow_auto_merge': False, 'delete_branch_on_merge': False, 'allow_update_branch': False, 'use_squash_pr_title_as_default': False, 'squash_merge_commit_message': 'COMMIT_MESSAGES', 'squash_merge_commit_title': 'COMMIT_OR_PR_TITLE', 'merge_commit_message': 'PR_TITLE', 'merge_commit_title': 'MERGE_MESSAGE'}}, '_links': {'self': {'href': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/14731'}, 'html': {'href': 'https://github.com/dolphin-emu/dolphin/pull/14731'}, 'issue': {'href': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/14731'}, 'comments': {'href': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/14731/comments'}, 'review_comments': {'href': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/14731/comments'}, 'review_comment': {'href': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/comments{/number}'}, 'commits': {'href': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/14731/commits'}, 'statuses': {'href': 'https://api.github.com/repos/dolphin-emu/dolphin/statuses/24b41d58df2315831b74f76b95417f2739d02f9d'}}, 'author_association': 'NONE', 'auto_merge': None, 'assignee': None, 'active_lock_reason': None}, 'repository': {'id': 11577304, 'node_id': 'MDEwOlJlcG9zaXRvcnkxMTU3NzMwNA==', 'name': 'dolphin', 'full_name': 'dolphin-emu/dolphin', 'private': False, 'owner': {'login': 'dolphin-emu', 'id': 5050316, 'node_id': 'MDEyOk9yZ2FuaXphdGlvbjUwNTAzMTY=', 'avatar_url': 'https://avatars.githubusercontent.com/u/5050316?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/dolphin-emu', 'html_url': 'https://github.com/dolphin-emu', 'followers_url': 'https://api.github.com/users/dolphin-emu/followers', 'following_url': 'https://api.github.com/users/dolphin-emu/following{/other_user}', 'gists_url': 'https://api.github.com/users/dolphin-emu/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/dolphin-emu/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/dolphin-emu/subscriptions', 'organizations_url': 'https://api.github.com/users/dolphin-emu/orgs', 'repos_url': 'https://api.github.com/users/dolphin-emu/repos', 'events_url': 'https://api.github.com/users/dolphin-emu/events{/privacy}', 'received_events_url': 'https://api.github.com/users/dolphin-emu/received_events', 'type': 'Organization', 'user_view_type': 'public', 'site_admin': False}, 'html_url': 'https://github.com/dolphin-emu/dolphin', 'description': 'Dolphin is a GameCube / Wii emulator, allowing you to play games for these two platforms on PC with improvements.', 'fork': False, 'url': 'https://api.github.com/repos/dolphin-emu/dolphin', 'forks_url': 'https://api.github.com/repos/dolphin-emu/dolphin/forks', 'keys_url': 'https://api.github.com/repos/dolphin-emu/dolphin/keys{/key_id}', 'collaborators_url': 'https://api.github.com/repos/dolphin-emu/dolphin/collaborators{/collaborator}', 'teams_url': 'https://api.github.com/repos/dolphin-emu/dolphin/teams', 'hooks_url': 'https://api.github.com/repos/dolphin-emu/dolphin/hooks', 'issue_events_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/events{/number}', 'events_url': 'https://api.github.com/repos/dolphin-emu/dolphin/events', 'assignees_url': 'https://api.github.com/repos/dolphin-emu/dolphin/assignees{/user}', 'branches_url': 'https://api.github.com/repos/dolphin-emu/dolphin/branches{/branch}', 'tags_url': 'https://api.github.com/repos/dolphin-emu/dolphin/tags', 'blobs_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/blobs{/sha}', 'git_tags_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/tags{/sha}', 'git_refs_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/refs{/sha}', 'trees_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/trees{/sha}', 'statuses_url': 'https://api.github.com/repos/dolphin-emu/dolphin/statuses/{sha}', 'languages_url': 'https://api.github.com/repos/dolphin-emu/dolphin/languages', 'stargazers_url': 'https://api.github.com/repos/dolphin-emu/dolphin/stargazers', 'contributors_url': 'https://api.github.com/repos/dolphin-emu/dolphin/contributors', 'subscribers_url': 'https://api.github.com/repos/dolphin-emu/dolphin/subscribers', 'subscription_url': 'https://api.github.com/repos/dolphin-emu/dolphin/subscription', 'commits_url': 'https://api.github.com/repos/dolphin-emu/dolphin/commits{/sha}', 'git_commits_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/commits{/sha}', 'comments_url': 'https://api.github.com/repos/dolphin-emu/dolphin/comments{/number}', 'issue_comment_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/comments{/number}', 'contents_url': 'https://api.github.com/repos/dolphin-emu/dolphin/contents/{+path}', 'compare_url': 'https://api.github.com/repos/dolphin-emu/dolphin/compare/{base}...{head}', 'merges_url': 'https://api.github.com/repos/dolphin-emu/dolphin/merges', 'archive_url': 'https://api.github.com/repos/dolphin-emu/dolphin/{archive_format}{/ref}', 'downloads_url': 'https://api.github.com/repos/dolphin-emu/dolphin/downloads', 'issues_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues{/number}', 'pulls_url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls{/number}', 'milestones_url': 'https://api.github.com/repos/dolphin-emu/dolphin/milestones{/number}', 'notifications_url': 'https://api.github.com/repos/dolphin-emu/dolphin/notifications{?since,all,participating}', 'labels_url': 'https://api.github.com/repos/dolphin-emu/dolphin/labels{/name}', 'releases_url': 'https://api.github.com/repos/dolphin-emu/dolphin/releases{/id}', 'deployments_url': 'https://api.github.com/repos/dolphin-emu/dolphin/deployments', 'created_at': '2013-07-22T09:07:57Z', 'updated_at': '2026-07-18T23:13:54Z', 'pushed_at': '2026-07-18T10:34:54Z', 'git_url': 'git://github.com/dolphin-emu/dolphin.git', 'ssh_url': 'git@github.com:dolphin-emu/dolphin.git', 'clone_url': 'https://github.com/dolphin-emu/dolphin.git', 'svn_url': 'https://github.com/dolphin-emu/dolphin', 'homepage': 'https://dolphin-emu.org', 'size': 558448, 'stargazers_count': 15273, 'watchers_count': 15273, 'language': 'C++', 'has_issues': False, 'has_projects': False, 'has_downloads': True, 'has_wiki': True, 'has_pages': False, 'has_discussions': False, 'forks_count': 3162, 'mirror_url': None, 'archived': False, 'disabled': False, 'open_issues_count': 446, 'license': {'key': 'other', 'name': 'Other', 'spdx_id': 'NOASSERTION', 'url': None, 'node_id': 'MDc6TGljZW5zZTA='}, 'allow_forking': True, 'is_template': False, 'web_commit_signoff_required': False, 'has_pull_requests': True, 'pull_request_creation_policy': 'all', 'topics': ['cpp', 'emulation', 'emulator', 'gamecube', 'wii'], 'visibility': 'public', 'forks': 3162, 'open_issues': 446, 'watchers': 15273, 'default_branch': 'master', 'custom_properties': {}}, 'organization': {'login': 'dolphin-emu', 'id': 5050316, 'node_id': 'MDEyOk9yZ2FuaXphdGlvbjUwNTAzMTY=', 'url': 'https://api.github.com/orgs/dolphin-emu', 'repos_url': 'https://api.github.com/orgs/dolphin-emu/repos', 'events_url': 'https://api.github.com/orgs/dolphin-emu/events', 'hooks_url': 'https://api.github.com/orgs/dolphin-emu/hooks', 'issues_url': 'https://api.github.com/orgs/dolphin-emu/issues', 'members_url': 'https://api.github.com/orgs/dolphin-emu/members{/member}', 'public_members_url': 'https://api.github.com/orgs/dolphin-emu/public_members{/member}', 'avatar_url': 'https://avatars.githubusercontent.com/u/5050316?v=4', 'description': ''}, 'sender': {'login': 'thethiny', 'id': 6018214, 'node_id': 'MDQ6VXNlcjYwMTgyMTQ=', 'avatar_url': 'https://avatars.githubusercontent.com/u/6018214?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/thethiny', 'html_url': 'https://github.com/thethiny', 'followers_url': 'https://api.github.com/users/thethiny/followers', 'following_url': 'https://api.github.com/users/thethiny/following{/other_user}', 'gists_url': 'https://api.github.com/users/thethiny/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/thethiny/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/thethiny/subscriptions', 'organizations_url': 'https://api.github.com/users/thethiny/orgs', 'repos_url': 'https://api.github.com/users/thethiny/repos', 'events_url': 'https://api.github.com/users/thethiny/events{/privacy}', 'received_events_url': 'https://api.github.com/users/thethiny/received_events', 'type': 'User', 'user_view_type': 'public', 'site_admin': False}, 'installation': {'id': 35437981, 'node_id': 'MDIzOkludGVncmF0aW9uSW5zdGFsbGF0aW9uMzU0Mzc5ODE='}}, 'type': 'raw_gh_hook'}
2026-07-18T23:36:12.676808	{'source': 'ghhookparser', 'repo': 'dolphin-emu/dolphin', 'author': 'thethiny', 'action': 'created', 'id': 14731, 'hash': '24b41d58df2315831b74f76b95417f2739d02f9d', 'url': 'https://github.com/dolphin-emu/dolphin/pull/14731#discussion_r3609417157', 'is_part_of_review': False, 'type': 'gh_pull_request_comment'}
2026-07-18T23:36:12.676082	{'source': 'webserver', 'gh_type': 'pull_request_review', 'raw': {'action': 'submitted', 'review': {'id': 4729499717, 'node_id': 'PRR_kwDOALCn2M8AAAABGeZwRQ', 'user': {'login': 'thethiny', 'id': 6018214, 'node_id': 'MDQ6VXNlcjYwMTgyMTQ=', 'avatar_url': 'https://avatars.githubusercontent.com/u/6018214?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/thethiny', 'html_url': 'https://github.com/thethiny', 'followers_url': 'https://api.github.com/users/thethiny/followers', 'following_url': 'https://api.github.com/users/thethiny/following{/other_user}', 'gists_url': 'https://api.github.com/users/thethiny/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/thethiny/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/thethiny/subscriptions', 'organizations_url': 'https://api.github.com/users/thethiny/orgs', 'repos_url': 'https://api.github.com/users/thethiny/repos', 'events_url': 'https://api.github.com/users/thethiny/events{/privacy}', 'received_events_url': 'https://api.github.com/users/thethiny/received_events', 'type': 'User', 'user_view_type': 'public', 'site_admin': False}, 'body': None, 'commit_id': '24b41d58df2315831b74f76b95417f2739d02f9d', 'state': 'commented', 'html_url': 'https://github.com/dolphin-emu/dolphin/pull/14731#pullrequestreview-4729499717', 'pull_request_url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/14731', '_links': {'html': {'href': 'https://github.com/dolphin-emu/dolphin/pull/14731#pullrequestreview-4729499717'}, 'pull_request': {'href': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/14731'}}, 'submitted_at': '2026-07-18T23:36:11Z', 'updated_at': '2026-07-18T23:36:11Z', 'author_association': 'NONE'}, 'pull_request': {'url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/14731', 'id': 4056977334, 'node_id': 'PR_kwDOALCn2M7x0I-2', 'html_url': 'https://github.com/dolphin-emu/dolphin/pull/14731', 'diff_url': 'https://github.com/dolphin-emu/dolphin/pull/14731.diff', 'patch_url': 'https://github.com/dolphin-emu/dolphin/pull/14731.patch', 'issue_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/14731', 'number': 14731, 'state': 'open', 'locked': False, 'title': 'Convert To WBFS Support', 'user': {'login': 'thethiny', 'id': 6018214, 'node_id': 'MDQ6VXNlcjYwMTgyMTQ=', 'avatar_url': 'https://avatars.githubusercontent.com/u/6018214?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/thethiny', 'html_url': 'https://github.com/thethiny', 'followers_url': 'https://api.github.com/users/thethiny/followers', 'following_url': 'https://api.github.com/users/thethiny/following{/other_user}', 'gists_url': 'https://api.github.com/users/thethiny/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/thethiny/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/thethiny/subscriptions', 'organizations_url': 'https://api.github.com/users/thethiny/orgs', 'repos_url': 'https://api.github.com/users/thethiny/repos', 'events_url': 'https://api.github.com/users/thethiny/events{/privacy}', 'received_events_url': 'https://api.github.com/users/thethiny/received_events', 'type': 'User', 'user_view_type': 'public', 'site_admin': False}, 'body': "This PR introduces Conversion **to** WBFS support. WBFS is the format that is used by USB Loaders on a real Wii device.\r\n\r\n## Design decisions & hardcoded values\r\nThe writer uses fixed sector sizes that match what [libwbfs (the reference implementation by kwiirk)](https://github.com/kwiirk/wbfs/blob/master/libwbfs/libwbfs.c#L128-L134) computes for a standard single-layer Wii disc. These 2 hardcodes are stable and work correctly across all my testings.\r\n- HD sector shift: 9 (512 bytes)\r\n- WBFS sector shift: 21 (2 MiB)\r\nThese are not configurable via the UI. All existing WBFS tools use these values, and since the aim is to support USB Loaders then this has been tested and it is working on a real Wii.\r\n\r\nConverting from WBFS is not enabled. The existing `WbfsFileReader` reports `DataSizeType::UpperBound`, and `ShouldAllowConversion()` requires `Accurate`. I am able to support this but since it was hardcoded by the Dolphin team I thought a discussion is warranted.\r\n\r\n## Testing\r\n- Verified with DolphinTool header and DolphinTool verify\r\n- Verified with wit FILETYPE and wit DUMP (Wiimm's ISO Tools recognizes valid WBFS structure, partitions, encryption)\r\n- Tested ISO to WBFS and RVZ to WBFS conversions\r\n- Output file sizes match Wii Backup Manager when scrubbing is enabled (~0.1% difference), works when scrubbing is disabled.\r\n- Output WBFS files play correctly in Dolphin\r\n- Output WBFS files play correctly on a real Wii using USB Loader GX e25c4f3\r\n", 'created_at': '2026-07-15T01:16:25Z', 'updated_at': '2026-07-18T23:33:13Z', 'closed_at': None, 'merged_at': None, 'merge_commit_sha': '228f93416dd80eb09da834ad7852c8eaa4d9212b', 'assignees': [], 'requested_reviewers': [], 'requested_teams': [], 'labels': [], 'milestone': None, 'draft': False, 'commits_url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/14731/commits', 'review_comments_url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/14731/comments', 'review_comment_url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/comments{/number}', 'comments_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/14731/comments', 'statuses_url': 'https://api.github.com/repos/dolphin-emu/dolphin/statuses/24b41d58df2315831b74f76b95417f2739d02f9d', 'head': {'label': 'thethiny:wbfs-conversion', 'ref': 'wbfs-conversion', 'sha': '24b41d58df2315831b74f76b95417f2739d02f9d', 'user': {'login': 'thethiny', 'id': 6018214, 'node_id': 'MDQ6VXNlcjYwMTgyMTQ=', 'avatar_url': 'https://avatars.githubusercontent.com/u/6018214?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/thethiny', 'html_url': 'https://github.com/thethiny', 'followers_url': 'https://api.github.com/users/thethiny/followers', 'following_url': 'https://api.github.com/users/thethiny/following{/other_user}', 'gists_url': 'https://api.github.com/users/thethiny/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/thethiny/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/thethiny/subscriptions', 'organizations_url': 'https://api.github.com/users/thethiny/orgs', 'repos_url': 'https://api.github.com/users/thethiny/repos', 'events_url': 'https://api.github.com/users/thethiny/events{/privacy}', 'received_events_url': 'https://api.github.com/users/thethiny/received_events', 'type': 'User', 'user_view_type': 'public', 'site_admin': False}, 'repo': {'id': 1298654395, 'node_id': 'R_kgDOTWfkuw', 'name': 'dolphin', 'full_name': 'thethiny/dolphin', 'private': False, 'owner': {'login': 'thethiny', 'id': 6018214, 'node_id': 'MDQ6VXNlcjYwMTgyMTQ=', 'avatar_url': 'https://avatars.githubusercontent.com/u/6018214?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/thethiny', 'html_url': 'https://github.com/thethiny', 'followers_url': 'https://api.github.com/users/thethiny/followers', 'following_url': 'https://api.github.com/users/thethiny/following{/other_user}', 'gists_url': 'https://api.github.com/users/thethiny/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/thethiny/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/thethiny/subscriptions', 'organizations_url': 'https://api.github.com/users/thethiny/orgs', 'repos_url': 'https://api.github.com/users/thethiny/repos', 'events_url': 'https://api.github.com/users/thethiny/events{/privacy}', 'received_events_url': 'https://api.github.com/users/thethiny/received_events', 'type': 'User', 'user_view_type': 'public', 'site_admin': False}, 'html_url': 'https://github.com/thethiny/dolphin', 'description': 'Dolphin is a GameCube / Wii emulator, allowing you to play games for these two platforms on PC with improvements.', 'fork': True, 'url': 'https://api.github.com/repos/thethiny/dolphin', 'forks_url': 'https://api.github.com/repos/thethiny/dolphin/forks', 'keys_url': 'https://api.github.com/repos/thethiny/dolphin/keys{/key_id}', 'collaborators_url': 'https://api.github.com/repos/thethiny/dolphin/collaborators{/collaborator}', 'teams_url': 'https://api.github.com/repos/thethiny/dolphin/teams', 'hooks_url': 'https://api.github.com/repos/thethiny/dolphin/hooks', 'issue_events_url': 'https://api.github.com/repos/thethiny/dolphin/issues/events{/number}', 'events_url': 'https://api.github.com/repos/thethiny/dolphin/events', 'assignees_url': 'https://api.github.com/repos/thethiny/dolphin/assignees{/user}', 'branches_url': 'https://api.github.com/repos/thethiny/dolphin/branches{/branch}', 'tags_url': 'https://api.github.com/repos/thethiny/dolphin/tags', 'blobs_url': 'https://api.github.com/repos/thethiny/dolphin/git/blobs{/sha}', 'git_tags_url': 'https://api.github.com/repos/thethiny/dolphin/git/tags{/sha}', 'git_refs_url': 'https://api.github.com/repos/thethiny/dolphin/git/refs{/sha}', 'trees_url': 'https://api.github.com/repos/thethiny/dolphin/git/trees{/sha}', 'statuses_url': 'https://api.github.com/repos/thethiny/dolphin/statuses/{sha}', 'languages_url': 'https://api.github.com/repos/thethiny/dolphin/languages', 'stargazers_url': 'https://api.github.com/repos/thethiny/dolphin/stargazers', 'contributors_url': 'https://api.github.com/repos/thethiny/dolphin/contributors', 'subscribers_url': 'https://api.github.com/repos/thethiny/dolphin/subscribers', 'subscription_url': 'https://api.github.com/repos/thethiny/dolphin/subscription', 'commits_url': 'https://api.github.com/repos/thethiny/dolphin/commits{/sha}', 'git_commits_url': 'https://api.github.com/repos/thethiny/dolphin/git/commits{/sha}', 'comments_url': 'https://api.github.com/repos/thethiny/dolphin/comments{/number}', 'issue_comment_url': 'https://api.github.com/repos/thethiny/dolphin/issues/comments{/number}', 'contents_url': 'https://api.github.com/repos/thethiny/dolphin/contents/{+path}', 'compare_url': 'https://api.github.com/repos/thethiny/dolphin/compare/{base}...{head}', 'merges_url': 'https://api.github.com/repos/thethiny/dolphin/merges', 'archive_url': 'https://api.github.com/repos/thethiny/dolphin/{archive_format}{/ref}', 'downloads_url': 'https://api.github.com/repos/thethiny/dolphin/downloads', 'issues_url': 'https://api.github.com/repos/thethiny/dolphin/issues{/number}', 'pulls_url': 'https://api.github.com/repos/thethiny/dolphin/pulls{/number}', 'milestones_url': 'https://api.github.com/repos/thethiny/dolphin/milestones{/number}', 'notifications_url': 'https://api.github.com/repos/thethiny/dolphin/notifications{?since,all,participating}', 'labels_url': 'https://api.github.com/repos/thethiny/dolphin/labels{/name}', 'releases_url': 'https://api.github.com/repos/thethiny/dolphin/releases{/id}', 'deployments_url': 'https://api.github.com/repos/thethiny/dolphin/deployments', 'created_at': '2026-07-12T22:09:13Z', 'updated_at': '2026-07-12T22:09:13Z', 'pushed_at': '2026-07-18T20:35:03Z', 'git_url': 'git://github.com/thethiny/dolphin.git', 'ssh_url': 'git@github.com:thethiny/dolphin.git', 'clone_url': 'https://github.com/thethiny/dolphin.git', 'svn_url': 'https://github.com/thethiny/dolphin', 'homepage': 'https://dolphin-emu.org', 'size': 515471, 'stargazers_count': 0, 'watchers_count': 0, 'language': None, 'has_issues': False, 'has_projects': True, 'has_downloads': True, 'has_wiki': True, 'has_pages': False, 'has_discussions': False, 'forks_count': 0, 'mirror_url': None, 'archived': False, 'disabled': False, 'open_issues_count': 0, 'license': {'key': 'other', 'name': 'Other', 'spdx_id': 'NOASSERTION', 'url': None, 'node_id': 'MDc6TGljZW5zZTA='}, 'allow_forking': True, 'is_template': False, 'web_commit_signoff_required': False, 'has_pull_requests': True, 'pull_request_creation_policy': 'all', 'topics': [], 'visibility': 'public', 'forks': 0, 'open_issues': 0, 'watchers': 0, 'default_branch': 'master', 'allow_squash_merge': True, 'allow_merge_commit': True, 'allow_rebase_merge': True, 'allow_auto_merge': False, 'delete_branch_on_merge': False, 'allow_update_branch': False, 'use_squash_pr_title_as_default': False, 'squash_merge_commit_message': 'COMMIT_MESSAGES', 'squash_merge_commit_title': 'COMMIT_OR_PR_TITLE', 'merge_commit_message': 'PR_TITLE', 'merge_commit_title': 'MERGE_MESSAGE'}}, 'base': {'label': 'dolphin-emu:master', 'ref': 'master', 'sha': 'd3b2943807dd0073f7767947466dd73cccfef319', 'user': {'login': 'dolphin-emu', 'id': 5050316, 'node_id': 'MDEyOk9yZ2FuaXphdGlvbjUwNTAzMTY=', 'avatar_url': 'https://avatars.githubusercontent.com/u/5050316?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/dolphin-emu', 'html_url': 'https://github.com/dolphin-emu', 'followers_url': 'https://api.github.com/users/dolphin-emu/followers', 'following_url': 'https://api.github.com/users/dolphin-emu/following{/other_user}', 'gists_url': 'https://api.github.com/users/dolphin-emu/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/dolphin-emu/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/dolphin-emu/subscriptions', 'organizations_url': 'https://api.github.com/users/dolphin-emu/orgs', 'repos_url': 'https://api.github.com/users/dolphin-emu/repos', 'events_url': 'https://api.github.com/users/dolphin-emu/events{/privacy}', 'received_events_url': 'https://api.github.com/users/dolphin-emu/received_events', 'type': 'Organization', 'user_view_type': 'public', 'site_admin': False}, 'repo': {'id': 11577304, 'node_id': 'MDEwOlJlcG9zaXRvcnkxMTU3NzMwNA==', 'name': 'dolphin', 'full_name': 'dolphin-emu/dolphin', 'private': False, 'owner': {'login': 'dolphin-emu', 'id': 5050316, 'node_id': 'MDEyOk9yZ2FuaXphdGlvbjUwNTAzMTY=', 'avatar_url': 'https://avatars.githubusercontent.com/u/5050316?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/dolphin-emu', 'html_url': 'https://github.com/dolphin-emu', 'followers_url': 'https://api.github.com/users/dolphin-emu/followers', 'following_url': 'https://api.github.com/users/dolphin-emu/following{/other_user}', 'gists_url': 'https://api.github.com/users/dolphin-emu/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/dolphin-emu/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/dolphin-emu/subscriptions', 'organizations_url': 'https://api.github.com/users/dolphin-emu/orgs', 'repos_url': 'https://api.github.com/users/dolphin-emu/repos', 'events_url': 'https://api.github.com/users/dolphin-emu/events{/privacy}', 'received_events_url': 'https://api.github.com/users/dolphin-emu/received_events', 'type': 'Organization', 'user_view_type': 'public', 'site_admin': False}, 'html_url': 'https://github.com/dolphin-emu/dolphin', 'description': 'Dolphin is a GameCube / Wii emulator, allowing you to play games for these two platforms on PC with improvements.', 'fork': False, 'url': 'https://api.github.com/repos/dolphin-emu/dolphin', 'forks_url': 'https://api.github.com/repos/dolphin-emu/dolphin/forks', 'keys_url': 'https://api.github.com/repos/dolphin-emu/dolphin/keys{/key_id}', 'collaborators_url': 'https://api.github.com/repos/dolphin-emu/dolphin/collaborators{/collaborator}', 'teams_url': 'https://api.github.com/repos/dolphin-emu/dolphin/teams', 'hooks_url': 'https://api.github.com/repos/dolphin-emu/dolphin/hooks', 'issue_events_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/events{/number}', 'events_url': 'https://api.github.com/repos/dolphin-emu/dolphin/events', 'assignees_url': 'https://api.github.com/repos/dolphin-emu/dolphin/assignees{/user}', 'branches_url': 'https://api.github.com/repos/dolphin-emu/dolphin/branches{/branch}', 'tags_url': 'https://api.github.com/repos/dolphin-emu/dolphin/tags', 'blobs_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/blobs{/sha}', 'git_tags_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/tags{/sha}', 'git_refs_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/refs{/sha}', 'trees_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/trees{/sha}', 'statuses_url': 'https://api.github.com/repos/dolphin-emu/dolphin/statuses/{sha}', 'languages_url': 'https://api.github.com/repos/dolphin-emu/dolphin/languages', 'stargazers_url': 'https://api.github.com/repos/dolphin-emu/dolphin/stargazers', 'contributors_url': 'https://api.github.com/repos/dolphin-emu/dolphin/contributors', 'subscribers_url': 'https://api.github.com/repos/dolphin-emu/dolphin/subscribers', 'subscription_url': 'https://api.github.com/repos/dolphin-emu/dolphin/subscription', 'commits_url': 'https://api.github.com/repos/dolphin-emu/dolphin/commits{/sha}', 'git_commits_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/commits{/sha}', 'comments_url': 'https://api.github.com/repos/dolphin-emu/dolphin/comments{/number}', 'issue_comment_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/comments{/number}', 'contents_url': 'https://api.github.com/repos/dolphin-emu/dolphin/contents/{+path}', 'compare_url': 'https://api.github.com/repos/dolphin-emu/dolphin/compare/{base}...{head}', 'merges_url': 'https://api.github.com/repos/dolphin-emu/dolphin/merges', 'archive_url': 'https://api.github.com/repos/dolphin-emu/dolphin/{archive_format}{/ref}', 'downloads_url': 'https://api.github.com/repos/dolphin-emu/dolphin/downloads', 'issues_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues{/number}', 'pulls_url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls{/number}', 'milestones_url': 'https://api.github.com/repos/dolphin-emu/dolphin/milestones{/number}', 'notifications_url': 'https://api.github.com/repos/dolphin-emu/dolphin/notifications{?since,all,participating}', 'labels_url': 'https://api.github.com/repos/dolphin-emu/dolphin/labels{/name}', 'releases_url': 'https://api.github.com/repos/dolphin-emu/dolphin/releases{/id}', 'deployments_url': 'https://api.github.com/repos/dolphin-emu/dolphin/deployments', 'created_at': '2013-07-22T09:07:57Z', 'updated_at': '2026-07-18T23:13:54Z', 'pushed_at': '2026-07-18T10:34:54Z', 'git_url': 'git://github.com/dolphin-emu/dolphin.git', 'ssh_url': 'git@github.com:dolphin-emu/dolphin.git', 'clone_url': 'https://github.com/dolphin-emu/dolphin.git', 'svn_url': 'https://github.com/dolphin-emu/dolphin', 'homepage': 'https://dolphin-emu.org', 'size': 558448, 'stargazers_count': 15273, 'watchers_count': 15273, 'language': 'C++', 'has_issues': False, 'has_projects': False, 'has_downloads': True, 'has_wiki': True, 'has_pages': False, 'has_discussions': False, 'forks_count': 3162, 'mirror_url': None, 'archived': False, 'disabled': False, 'open_issues_count': 446, 'license': {'key': 'other', 'name': 'Other', 'spdx_id': 'NOASSERTION', 'url': None, 'node_id': 'MDc6TGljZW5zZTA='}, 'allow_forking': True, 'is_template': False, 'web_commit_signoff_required': False, 'has_pull_requests': True, 'pull_request_creation_policy': 'all', 'topics': ['cpp', 'emulation', 'emulator', 'gamecube', 'wii'], 'visibility': 'public', 'forks': 3162, 'open_issues': 446, 'watchers': 15273, 'default_branch': 'master', 'allow_squash_merge': False, 'allow_merge_commit': True, 'allow_rebase_merge': False, 'allow_auto_merge': False, 'delete_branch_on_merge': False, 'allow_update_branch': False, 'use_squash_pr_title_as_default': False, 'squash_merge_commit_message': 'COMMIT_MESSAGES', 'squash_merge_commit_title': 'COMMIT_OR_PR_TITLE', 'merge_commit_message': 'PR_TITLE', 'merge_commit_title': 'MERGE_MESSAGE'}}, '_links': {'self': {'href': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/14731'}, 'html': {'href': 'https://github.com/dolphin-emu/dolphin/pull/14731'}, 'issue': {'href': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/14731'}, 'comments': {'href': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/14731/comments'}, 'review_comments': {'href': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/14731/comments'}, 'review_comment': {'href': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/comments{/number}'}, 'commits': {'href': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/14731/commits'}, 'statuses': {'href': 'https://api.github.com/repos/dolphin-emu/dolphin/statuses/24b41d58df2315831b74f76b95417f2739d02f9d'}}, 'author_association': 'NONE', 'auto_merge': None, 'assignee': None, 'active_lock_reason': None}, 'repository': {'id': 11577304, 'node_id': 'MDEwOlJlcG9zaXRvcnkxMTU3NzMwNA==', 'name': 'dolphin', 'full_name': 'dolphin-emu/dolphin', 'private': False, 'owner': {'login': 'dolphin-emu', 'id': 5050316, 'node_id': 'MDEyOk9yZ2FuaXphdGlvbjUwNTAzMTY=', 'avatar_url': 'https://avatars.githubusercontent.com/u/5050316?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/dolphin-emu', 'html_url': 'https://github.com/dolphin-emu', 'followers_url': 'https://api.github.com/users/dolphin-emu/followers', 'following_url': 'https://api.github.com/users/dolphin-emu/following{/other_user}', 'gists_url': 'https://api.github.com/users/dolphin-emu/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/dolphin-emu/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/dolphin-emu/subscriptions', 'organizations_url': 'https://api.github.com/users/dolphin-emu/orgs', 'repos_url': 'https://api.github.com/users/dolphin-emu/repos', 'events_url': 'https://api.github.com/users/dolphin-emu/events{/privacy}', 'received_events_url': 'https://api.github.com/users/dolphin-emu/received_events', 'type': 'Organization', 'user_view_type': 'public', 'site_admin': False}, 'html_url': 'https://github.com/dolphin-emu/dolphin', 'description': 'Dolphin is a GameCube / Wii emulator, allowing you to play games for these two platforms on PC with improvements.', 'fork': False, 'url': 'https://api.github.com/repos/dolphin-emu/dolphin', 'forks_url': 'https://api.github.com/repos/dolphin-emu/dolphin/forks', 'keys_url': 'https://api.github.com/repos/dolphin-emu/dolphin/keys{/key_id}', 'collaborators_url': 'https://api.github.com/repos/dolphin-emu/dolphin/collaborators{/collaborator}', 'teams_url': 'https://api.github.com/repos/dolphin-emu/dolphin/teams', 'hooks_url': 'https://api.github.com/repos/dolphin-emu/dolphin/hooks', 'issue_events_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/events{/number}', 'events_url': 'https://api.github.com/repos/dolphin-emu/dolphin/events', 'assignees_url': 'https://api.github.com/repos/dolphin-emu/dolphin/assignees{/user}', 'branches_url': 'https://api.github.com/repos/dolphin-emu/dolphin/branches{/branch}', 'tags_url': 'https://api.github.com/repos/dolphin-emu/dolphin/tags', 'blobs_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/blobs{/sha}', 'git_tags_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/tags{/sha}', 'git_refs_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/refs{/sha}', 'trees_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/trees{/sha}', 'statuses_url': 'https://api.github.com/repos/dolphin-emu/dolphin/statuses/{sha}', 'languages_url': 'https://api.github.com/repos/dolphin-emu/dolphin/languages', 'stargazers_url': 'https://api.github.com/repos/dolphin-emu/dolphin/stargazers', 'contributors_url': 'https://api.github.com/repos/dolphin-emu/dolphin/contributors', 'subscribers_url': 'https://api.github.com/repos/dolphin-emu/dolphin/subscribers', 'subscription_url': 'https://api.github.com/repos/dolphin-emu/dolphin/subscription', 'commits_url': 'https://api.github.com/repos/dolphin-emu/dolphin/commits{/sha}', 'git_commits_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/commits{/sha}', 'comments_url': 'https://api.github.com/repos/dolphin-emu/dolphin/comments{/number}', 'issue_comment_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/comments{/number}', 'contents_url': 'https://api.github.com/repos/dolphin-emu/dolphin/contents/{+path}', 'compare_url': 'https://api.github.com/repos/dolphin-emu/dolphin/compare/{base}...{head}', 'merges_url': 'https://api.github.com/repos/dolphin-emu/dolphin/merges', 'archive_url': 'https://api.github.com/repos/dolphin-emu/dolphin/{archive_format}{/ref}', 'downloads_url': 'https://api.github.com/repos/dolphin-emu/dolphin/downloads', 'issues_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues{/number}', 'pulls_url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls{/number}', 'milestones_url': 'https://api.github.com/repos/dolphin-emu/dolphin/milestones{/number}', 'notifications_url': 'https://api.github.com/repos/dolphin-emu/dolphin/notifications{?since,all,participating}', 'labels_url': 'https://api.github.com/repos/dolphin-emu/dolphin/labels{/name}', 'releases_url': 'https://api.github.com/repos/dolphin-emu/dolphin/releases{/id}', 'deployments_url': 'https://api.github.com/repos/dolphin-emu/dolphin/deployments', 'created_at': '2013-07-22T09:07:57Z', 'updated_at': '2026-07-18T23:13:54Z', 'pushed_at': '2026-07-18T10:34:54Z', 'git_url': 'git://github.com/dolphin-emu/dolphin.git', 'ssh_url': 'git@github.com:dolphin-emu/dolphin.git', 'clone_url': 'https://github.com/dolphin-emu/dolphin.git', 'svn_url': 'https://github.com/dolphin-emu/dolphin', 'homepage': 'https://dolphin-emu.org', 'size': 558448, 'stargazers_count': 15273, 'watchers_count': 15273, 'language': 'C++', 'has_issues': False, 'has_projects': False, 'has_downloads': True, 'has_wiki': True, 'has_pages': False, 'has_discussions': False, 'forks_count': 3162, 'mirror_url': None, 'archived': False, 'disabled': False, 'open_issues_count': 446, 'license': {'key': 'other', 'name': 'Other', 'spdx_id': 'NOASSERTION', 'url': None, 'node_id': 'MDc6TGljZW5zZTA='}, 'allow_forking': True, 'is_template': False, 'web_commit_signoff_required': False, 'has_pull_requests': True, 'pull_request_creation_policy': 'all', 'topics': ['cpp', 'emulation', 'emulator', 'gamecube', 'wii'], 'visibility': 'public', 'forks': 3162, 'open_issues': 446, 'watchers': 15273, 'default_branch': 'master', 'custom_properties': {}}, 'organization': {'login': 'dolphin-emu', 'id': 5050316, 'node_id': 'MDEyOk9yZ2FuaXphdGlvbjUwNTAzMTY=', 'url': 'https://api.github.com/orgs/dolphin-emu', 'repos_url': 'https://api.github.com/orgs/dolphin-emu/repos', 'events_url': 'https://api.github.com/orgs/dolphin-emu/events', 'hooks_url': 'https://api.github.com/orgs/dolphin-emu/hooks', 'issues_url': 'https://api.github.com/orgs/dolphin-emu/issues', 'members_url': 'https://api.github.com/orgs/dolphin-emu/members{/member}', 'public_members_url': 'https://api.github.com/orgs/dolphin-emu/public_members{/member}', 'avatar_url': 'https://avatars.githubusercontent.com/u/5050316?v=4', 'description': ''}, 'sender': {'login': 'thethiny', 'id': 6018214, 'node_id': 'MDQ6VXNlcjYwMTgyMTQ=', 'avatar_url': 'https://avatars.githubusercontent.com/u/6018214?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/thethiny', 'html_url': 'https://github.com/thethiny', 'followers_url': 'https://api.github.com/users/thethiny/followers', 'following_url': 'https://api.github.com/users/thethiny/following{/other_user}', 'gists_url': 'https://api.github.com/users/thethiny/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/thethiny/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/thethiny/subscriptions', 'organizations_url': 'https://api.github.com/users/thethiny/orgs', 'repos_url': 'https://api.github.com/users/thethiny/repos', 'events_url': 'https://api.github.com/users/thethiny/events{/privacy}', 'received_events_url': 'https://api.github.com/users/thethiny/received_events', 'type': 'User', 'user_view_type': 'public', 'site_admin': False}, 'installation': {'id': 35437981, 'node_id': 'MDIzOkludGVncmF0aW9uSW5zdGFsbGF0aW9uMzU0Mzc5ODE='}}, 'type': 'raw_gh_hook'}
2026-07-18T23:36:12.676066	{'source': 'ghhookparser', 'repo': 'dolphin-emu/dolphin', 'author': 'thethiny', 'action': 'submitted', 'pr_id': 14731, 'pr_title': 'Convert To WBFS Support', 'state': 'commented', 'url': 'https://github.com/dolphin-emu/dolphin/pull/14731#pullrequestreview-4729499717', 'comments': [{'id': 3609417157, 'node_id': 'PRRC_kwDOALCn2M7XI1XF', 'url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/comments/3609417157', 'pull_request_review_id': 4729499717, 'diff_hunk': '@@ -119,22 +144,191 @@ bool WbfsFileReader::ReadHeader()\n   return m_header.disc_table[0] != 0;\n }\n \n+bool WbfsFileReader::ReadNKitHeader()\n+{\n+  const u64 gap_type_blocks = (DL_DVD_SIZE + m_wbfs_sector_size - 1) / m_wbfs_sector_size;\n+  m_nkit_info = NKit::ReadHeaderFromFile(m_files[0].file, NKit::HEADER_OFFSET, gap_type_blocks);\n+  if (!m_nkit_info.valid)\n+    return false;\n+\n+  m_has_nkit_header = true;\n+  return true;\n+}\n+\n+bool WbfsFileReader::IsBlockStored(u64 block_index) const\n+{\n+  return block_index < m_blocks_per_disc && m_wlba_table[block_index] != 0;\n+}\n+\n+bool WbfsFileReader::IsGapJunk(u64 block_index) const\n+{\n+  return NKit::IsGapJunk(m_nkit_info.gap_type, block_index);\n+}\n+\n+void WbfsFileReader::GenerateJunkData(u64 disc_offset, u64 size, u8* out) const\n+{\n+  LaggedFibonacciGenerator::FillJunkData(out, static_cast<size_t>(size), disc_offset, m_disc_id,\n+                                         m_disc_num);\n+}\n+\n+void WbfsFileReader::ReadPartitionInfo()\n+{\n+  std::unique_ptr<VolumeDisc> volume = CreateDisc(CopyReader());\n+  if (!volume)\n+    return;\n+\n+  for (const Partition& partition : volume->GetPartitions())\n+  {\n+    const auto& ticket = volume->GetTicket(partition);\n+    const std::array<u8, 16> title_key = ticket.GetTitleKey();\n+\n+    u8 data_info[8];\n+    if (!Read(partition.offset + 0x2B8, 8, data_info))\n+      continue;\n+\n+    PartitionEntry entry;\n+    entry.data_offset = partition.offset + (static_cast<u64>(Common::swap32(data_info)) << 2);\n+    entry.data_size = static_cast<u64>(Common::swap32(data_info + 4)) << 2;\n+    entry.key = title_key;\n+    m_partitions.push_back(entry);\n+  }\n+}\n+\n+const WbfsFileReader::PartitionEntry* WbfsFileReader::FindPartition(u64 disc_offset) const\n+{\n+  for (const auto& p : m_partitions)\n+  {\n+    if (disc_offset >= p.data_offset && disc_offset < p.data_offset + p.data_size)\n+      return &p;\n+  }\n+  return nullptr;\n+}\n+\n+const WbfsFileReader::PartitionEntry*\n+WbfsFileReader::FindPartitionByDataOffset(u64 partition_data_offset) const\n+{\n+  for (const auto& p : m_partitions)\n+  {\n+    if (p.data_offset == partition_data_offset)\n+      return &p;\n+  }\n+  return nullptr;\n+}\n+\n+bool WbfsFileReader::SupportsReadWiiDecrypted(u64 offset, u64 size, u64 partition_data_offset) const\n+{\n+  if (!m_has_nkit_header)\n+    return false;\n+\n+  const u64 block_in_partition = offset / VolumeWii::BLOCK_DATA_SIZE;\n+  const u64 disc_offset = partition_data_offset + block_in_partition * VolumeWii::BLOCK_TOTAL_SIZE;\n+  const u64 wbfs_block = disc_offset >> m_header.wbfs_sector_shift;\n+\n+  return wbfs_block < m_blocks_per_disc && !IsBlockStored(wbfs_block);\n+}\n+\n+bool WbfsFileReader::ReadWiiDecrypted(u64 offset, u64 size, u8* out_ptr, u64 partition_data_offset)\n+{\n+  const PartitionEntry* pe = FindPartitionByDataOffset(partition_data_offset);\n+  if (!pe)\n+    return false;\n+\n+  auto aes_ctx = Common::AES::CreateContextDecrypt(pe->key.data());\n+  std::vector<u8> encrypted(VolumeWii::BLOCK_TOTAL_SIZE);\n+  std::vector<u8> decrypted(VolumeWii::BLOCK_DATA_SIZE);\n+\n+  while (size > 0)\n+  {\n+    const u64 block_in_partition = offset / VolumeWii::BLOCK_DATA_SIZE;\n+    const u64 offset_in_block = offset % VolumeWii::BLOCK_DATA_SIZE;\n+    const u64 bytes_in_block = VolumeWii::BLOCK_DATA_SIZE - offset_in_block;\n+    const size_t read_size = static_cast<size_t>(std::min(bytes_in_block, size));\n+\n+    const u64 disc_offset =\n+        partition_data_offset + block_in_partition * VolumeWii::BLOCK_TOTAL_SIZE;\n+    const u64 wbfs_block = disc_offset >> m_header.wbfs_sector_shift;\n+\n+    if (IsBlockStored(wbfs_block))\n+    {\n+      u64 available;\n+      auto& file = SeekToCluster(disc_offset, &available);\n+      if (available < VolumeWii::BLOCK_TOTAL_SIZE ||\n+          !file.Read(encrypted.data(), VolumeWii::BLOCK_TOTAL_SIZE))\n+        return false;\n+      VolumeWii::DecryptBlockData(encrypted.data(), decrypted.data(), aes_ctx.get());\n+      std::memcpy(out_ptr, decrypted.data() + offset_in_block, read_size);\n+    }', 'path': 'Source/Core/DiscIO/WbfsBlob.cpp', 'position': 204, 'original_position': 204, 'commit_id': '24b41d58df2315831b74f76b95417f2739d02f9d', 'user': {'login': 'thethiny', 'id': 6018214, 'node_id': 'MDQ6VXNlcjYwMTgyMTQ=', 'avatar_url': 'https://avatars.githubusercontent.com/u/6018214?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/thethiny', 'html_url': 'https://github.com/thethiny', 'followers_url': 'https://api.github.com/users/thethiny/followers', 'following_url': 'https://api.github.com/users/thethiny/following{/other_user}', 'gists_url': 'https://api.github.com/users/thethiny/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/thethiny/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/thethiny/subscriptions', 'organizations_url': 'https://api.github.com/users/thethiny/orgs', 'repos_url': 'https://api.github.com/users/thethiny/repos', 'events_url': 'https://api.github.com/users/thethiny/events{/privacy}', 'received_events_url': 'https://api.github.com/users/thethiny/received_events', 'type': 'User', 'user_view_type': 'public', 'site_admin': False}, 'body': 'This needs an investigation, since EncryptGroup processes about 64 sectors and therefore the sectors could be a mix of stored and non-stored blocks. It is possible that this path will never hit but I cannot confirm that since I did not test it out. I will do so and report back with either a fix or a result.', 'created_at': '2026-07-18T23:36:11Z', 'updated_at': '2026-07-18T23:36:11Z', 'html_url': 'https://github.com/dolphin-emu/dolphin/pull/14731#discussion_r3609417157', 'pull_request_url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/14731', 'author_association': 'NONE', '_links': {'self': {'href': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/comments/3609417157'}, 'html': {'href': 'https://github.com/dolphin-emu/dolphin/pull/14731#discussion_r3609417157'}, 'pull_request': {'href': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/14731'}}, 'original_commit_id': '24b41d58df2315831b74f76b95417f2739d02f9d', 'reactions': {'url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/comments/3609417157/reactions', 'total_count': 0, '+1': 0, '-1': 0, 'laugh': 0, 'hooray': 0, 'confused': 0, 'heart': 0, 'rocket': 0, 'eyes': 0}, 'in_reply_to_id': 3609277919}], 'type': 'gh_pull_request_review'}
2026-07-18T23:36:09.276883	{'source': 'logging', 'level': 'INFO', 'pathname': '/nix/store/m89a38mxx677zd2j3gqq91c40d1i7dc6-central-env/lib/python3.13/site-packages/central/github/authz.py', 'lineno': 30, 'msg': 'New GH %s: %s', 'args': "('dolphin-emu/core-developers', 'lioncash,Pokechu22,degasus,Helios747,iwubcode,spycrab,linkmauve,skidau,AdmiralCurtiss,Tilka,leoetlino,Parlane,JosJuice,Dentomologist,OatmealDome,phire,CrossVR,delroth,hrydgard,jordan-woyak')", 'type': 'internal_log'}

Recent 'build_status' events

2026-07-18T20:59:49.016041	{'source': 'buildbot', 'repo': 'dolphin-emu/dolphin', 'hash': '24b41d58df2315831b74f76b95417f2739d02f9d', 'shortrev': '24b41d', 'service': 'pr-osx-universal', 'pr': 14731, 'success': True, 'pending': False, 'url': 'https://dolphin.ci/#/builders/7/builds/10074', 'description': 'Build succeeded on builder pr-osx-universal', 'type': 'build_status'}
2026-07-18T20:51:39.554999	{'source': 'buildbot', 'repo': 'dolphin-emu/dolphin', 'hash': '24b41d58df2315831b74f76b95417f2739d02f9d', 'shortrev': '24b41d', 'service': 'pr-android', 'pr': 14731, 'success': True, 'pending': False, 'url': 'https://dolphin.ci/#/builders/22/builds/10061', 'description': 'Build succeeded on builder pr-android', 'type': 'build_status'}
2026-07-18T20:45:05.488654	{'source': 'buildbot', 'repo': 'dolphin-emu/dolphin', 'hash': '24b41d58df2315831b74f76b95417f2739d02f9d', 'shortrev': '24b41d', 'service': 'pr-deb-dbg-x64', 'pr': 14731, 'success': True, 'pending': False, 'url': 'https://dolphin.ci/#/builders/1/builds/10060', 'description': 'Build succeeded on builder pr-deb-dbg-x64', 'type': 'build_status'}
2026-07-18T20:44:10.517988	{'source': 'buildbot', 'repo': 'dolphin-emu/dolphin', 'hash': '24b41d58df2315831b74f76b95417f2739d02f9d', 'shortrev': '24b41d', 'service': 'pr-flatpak-x64', 'pr': 14731, 'success': True, 'pending': False, 'url': 'https://dolphin.ci/#/builders/43/builds/5204', 'description': 'Build succeeded on builder pr-flatpak-x64', 'type': 'build_status'}
2026-07-18T20:43:46.724135	{'source': 'buildbot', 'repo': 'dolphin-emu/dolphin', 'hash': '24b41d58df2315831b74f76b95417f2739d02f9d', 'shortrev': '24b41d', 'service': 'pr-flatpak-arm64', 'pr': 14731, 'success': True, 'pending': False, 'url': 'https://dolphin.ci/#/builders/44/builds/5148', 'description': 'Build succeeded on builder pr-flatpak-arm64', 'type': 'build_status'}
2026-07-18T20:43:46.118575	{'source': 'buildbot', 'repo': 'dolphin-emu/dolphin', 'hash': '24b41d58df2315831b74f76b95417f2739d02f9d', 'shortrev': '24b41d', 'service': 'pr-win-dbg-x64', 'pr': 14731, 'success': False, 'pending': False, 'url': 'https://dolphin.ci/#/builders/31/builds/10068', 'description': 'Build failed on builder pr-win-dbg-x64', 'type': 'build_status'}
2026-07-18T20:42:55.013086	{'source': 'buildbot', 'repo': 'dolphin-emu/dolphin', 'hash': '24b41d58df2315831b74f76b95417f2739d02f9d', 'shortrev': '24b41d', 'service': 'pr-deb-dbg-x64', 'pr': 14731, 'success': False, 'pending': True, 'url': 'https://dolphin.ci/#/builders/1/builds/10060', 'description': 'Auto build in progress on builder pr-deb-dbg-x64', 'type': 'build_status'}
2026-07-18T20:42:54.554235	{'source': 'buildbot', 'repo': 'dolphin-emu/dolphin', 'hash': '24b41d58df2315831b74f76b95417f2739d02f9d', 'shortrev': '24b41d', 'service': 'pr-deb-x64', 'pr': 14731, 'success': True, 'pending': False, 'url': 'https://dolphin.ci/#/builders/26/builds/10058', 'description': 'Build succeeded on builder pr-deb-x64', 'type': 'build_status'}
2026-07-18T20:42:44.650051	{'source': 'buildbot', 'repo': 'dolphin-emu/dolphin', 'hash': '24b41d58df2315831b74f76b95417f2739d02f9d', 'shortrev': '24b41d', 'service': 'pr-win-dbg-x64', 'pr': 14731, 'success': False, 'pending': True, 'url': 'https://dolphin.ci/#/builders/31/builds/10068', 'description': 'Auto build in progress on builder pr-win-dbg-x64', 'type': 'build_status'}
2026-07-18T20:42:44.354017	{'source': 'buildbot', 'repo': 'dolphin-emu/dolphin', 'hash': '24b41d58df2315831b74f76b95417f2739d02f9d', 'shortrev': '24b41d', 'service': 'pr-win-x64', 'pr': 14731, 'success': False, 'pending': False, 'url': 'https://dolphin.ci/#/builders/2/builds/10061', 'description': 'Build failed on builder pr-win-x64', 'type': 'build_status'}
2026-07-18T20:41:39.642984	{'source': 'buildbot', 'repo': 'dolphin-emu/dolphin', 'hash': '24b41d58df2315831b74f76b95417f2739d02f9d', 'shortrev': '24b41d', 'service': 'pr-win-x64', 'pr': 14731, 'success': False, 'pending': True, 'url': 'https://dolphin.ci/#/builders/2/builds/10061', 'description': 'Auto build in progress on builder pr-win-x64', 'type': 'build_status'}
2026-07-18T20:41:39.114766	{'source': 'buildbot', 'repo': 'dolphin-emu/dolphin', 'hash': '24b41d58df2315831b74f76b95417f2739d02f9d', 'shortrev': '24b41d', 'service': 'pr-win-arm64', 'pr': 14731, 'success': False, 'pending': False, 'url': 'https://dolphin.ci/#/builders/13/builds/10058', 'description': 'Build failed on builder pr-win-arm64', 'type': 'build_status'}
2026-07-18T20:41:11.671207	{'source': 'buildbot', 'repo': 'dolphin-emu/dolphin', 'hash': '24b41d58df2315831b74f76b95417f2739d02f9d', 'shortrev': '24b41d', 'service': 'lint', 'pr': 14731, 'success': True, 'pending': False, 'url': 'https://dolphin.ci/#/builders/9/builds/10058', 'description': 'Build succeeded on builder lint', 'type': 'build_status'}
2026-07-18T20:41:08.287862	{'source': 'buildbot', 'repo': 'dolphin-emu/dolphin', 'hash': '24b41d58df2315831b74f76b95417f2739d02f9d', 'shortrev': '24b41d', 'service': 'pr-ubu-x64', 'pr': 14731, 'success': True, 'pending': False, 'url': 'https://dolphin.ci/#/builders/27/builds/10059', 'description': 'Build succeeded on builder pr-ubu-x64', 'type': 'build_status'}
2026-07-18T20:41:02.796011	{'source': 'buildbot', 'repo': 'dolphin-emu/dolphin', 'hash': '24b41d58df2315831b74f76b95417f2739d02f9d', 'shortrev': '24b41d', 'service': 'pr-freebsd-x64', 'pr': 14731, 'success': True, 'pending': False, 'url': 'https://dolphin.ci/#/builders/11/builds/10064', 'description': 'Build succeeded on builder pr-freebsd-x64', 'type': 'build_status'}
2026-07-18T20:40:48.090676	{'source': 'buildbot', 'repo': 'dolphin-emu/dolphin', 'hash': '24b41d58df2315831b74f76b95417f2739d02f9d', 'shortrev': '24b41d', 'service': 'lint', 'pr': 14731, 'success': False, 'pending': True, 'url': 'https://dolphin.ci/#/builders/9/builds/10058', 'description': 'Auto build in progress on builder lint', 'type': 'build_status'}
2026-07-18T20:40:33.400363	{'source': 'buildbot', 'repo': 'dolphin-emu/dolphin', 'hash': '24b41d58df2315831b74f76b95417f2739d02f9d', 'shortrev': '24b41d', 'service': 'pr-ubu-x64', 'pr': 14731, 'success': False, 'pending': True, 'url': 'https://dolphin.ci/#/builders/27/builds/10059', 'description': 'Auto build in progress on builder pr-ubu-x64', 'type': 'build_status'}
2026-07-18T20:40:29.988701	{'source': 'buildbot', 'repo': 'dolphin-emu/dolphin', 'hash': '24b41d58df2315831b74f76b95417f2739d02f9d', 'shortrev': '24b41d', 'service': 'pr-osx-universal', 'pr': 14731, 'success': False, 'pending': True, 'url': 'https://dolphin.ci/#/builders/7/builds/10074', 'description': 'Auto build in progress on builder pr-osx-universal', 'type': 'build_status'}
2026-07-18T20:40:29.528872	{'source': 'buildbot', 'repo': 'dolphin-emu/dolphin', 'hash': '24b41d58df2315831b74f76b95417f2739d02f9d', 'shortrev': '24b41d', 'service': 'pr-deb-x64', 'pr': 14731, 'success': False, 'pending': True, 'url': 'https://dolphin.ci/#/builders/26/builds/10058', 'description': 'Auto build in progress on builder pr-deb-x64', 'type': 'build_status'}
2026-07-18T20:40:29.076612	{'source': 'buildbot', 'repo': 'dolphin-emu/dolphin', 'hash': '24b41d58df2315831b74f76b95417f2739d02f9d', 'shortrev': '24b41d', 'service': 'pr-android', 'pr': 14731, 'success': False, 'pending': True, 'url': 'https://dolphin.ci/#/builders/22/builds/10061', 'description': 'Auto build in progress on builder pr-android', 'type': 'build_status'}
2026-07-18T20:40:28.816934	{'source': 'buildbot', 'repo': 'dolphin-emu/dolphin', 'hash': '24b41d58df2315831b74f76b95417f2739d02f9d', 'shortrev': '24b41d', 'service': 'pr-freebsd-x64', 'pr': 14731, 'success': False, 'pending': True, 'url': 'https://dolphin.ci/#/builders/11/builds/10064', 'description': 'Auto build in progress on builder pr-freebsd-x64', 'type': 'build_status'}
2026-07-18T20:40:28.536207	{'source': 'buildbot', 'repo': 'dolphin-emu/dolphin', 'hash': '24b41d58df2315831b74f76b95417f2739d02f9d', 'shortrev': '24b41d', 'service': 'pr-flatpak-x64', 'pr': 14731, 'success': False, 'pending': True, 'url': 'https://dolphin.ci/#/builders/43/builds/5204', 'description': 'Auto build in progress on builder pr-flatpak-x64', 'type': 'build_status'}
2026-07-18T20:40:28.074085	{'source': 'buildbot', 'repo': 'dolphin-emu/dolphin', 'hash': '24b41d58df2315831b74f76b95417f2739d02f9d', 'shortrev': '24b41d', 'service': 'pr-flatpak-arm64', 'pr': 14731, 'success': False, 'pending': True, 'url': 'https://dolphin.ci/#/builders/44/builds/5148', 'description': 'Auto build in progress on builder pr-flatpak-arm64', 'type': 'build_status'}
2026-07-18T20:40:27.619541	{'source': 'buildbot', 'repo': 'dolphin-emu/dolphin', 'hash': '24b41d58df2315831b74f76b95417f2739d02f9d', 'shortrev': '24b41d', 'service': 'pr-win-arm64', 'pr': 14731, 'success': False, 'pending': True, 'url': 'https://dolphin.ci/#/builders/13/builds/10058', 'description': 'Auto build in progress on builder pr-win-arm64', 'type': 'build_status'}
2026-07-18T20:40:26.557167	{'source': 'prbuilder', 'repo': 'dolphin-emu/dolphin', 'hash': '24b41d58df2315831b74f76b95417f2739d02f9d', 'shortrev': '24b41d', 'service': 'lint', 'pr': 14731, 'success': False, 'pending': True, 'url': 'https://dolphin.ci/', 'description': 'Auto build pending', 'type': 'build_status'}

Recent 'command_message' events

2026-07-18T20:40:17.957187	{'source': 'discord', 'who': 'josjuice', 'what': '<@1320924779556900984> please rebuild 14731', 'type': 'command_message'}
2026-07-18T19:43:51.176666	{'source': 'discord', 'who': 'josjuice', 'what': '<@1320924779556900984> please rebuild 14731', 'type': 'command_message'}
2026-07-18T02:39:47.246484	{'source': 'discord', 'who': 'phirenz', 'what': '<@1320924779556900984> please rebuild 14731', 'type': 'command_message'}
2026-07-17T00:44:12.110187	{'source': 'discord', 'who': 'phirenz', 'what': '<@1320924779556900984> please rebuild 14028', 'type': 'command_message'}
2026-07-15T19:11:54.747296	{'source': 'discord', 'who': 'billiard26', 'what': '<@1320924779556900984> please rebuild PR 14436', 'type': 'command_message'}
2026-07-15T18:38:24.658851	{'source': 'discord', 'who': 'joshuavandaele', 'what': '<@1320924779556900984> please rebuild 14436', 'type': 'command_message'}
2026-07-15T16:47:20.416069	{'source': 'discord', 'who': 'josjuice', 'what': '<@1320924779556900984> please rebuild 14436', 'type': 'command_message'}
2026-07-15T16:21:33.194001	{'source': 'discord', 'who': 'josjuice', 'what': '<@1320924779556900984> please rebuild 14732', 'type': 'command_message'}
2026-07-15T01:29:51.907251	{'source': 'discord', 'who': 'joshuavandaele', 'what': '<@1320924779556900984> please rebuild 14652', 'type': 'command_message'}
2026-07-14T19:08:46.196717	{'source': 'discord', 'who': 'josjuice', 'what': '<@1320924779556900984> please rebuild 14652', 'type': 'command_message'}
2026-07-14T16:34:50.490321	{'source': 'discord', 'who': 'josjuice', 'what': '<@1320924779556900984> please rebuild 14652', 'type': 'command_message'}
2026-07-12T21:11:16.985005	{'source': 'discord', 'who': 'josjuice', 'what': '<@1320924779556900984> please rebuild 14436', 'type': 'command_message'}
2026-07-12T07:11:51.848596	{'source': 'discord', 'who': 'josjuice', 'what': '<@1320924779556900984> please rebuild 14722', 'type': 'command_message'}
2026-07-12T07:11:38.938021	{'source': 'discord', 'who': 'josjuice', 'what': '<@1320924779556900984> please rebuild 14725', 'type': 'command_message'}
2026-07-12T05:14:19.935358	{'source': 'discord', 'who': 'phirenz', 'what': '<@1320924779556900984> please rebuild 14724', 'type': 'command_message'}
2026-07-12T04:30:26.557604	{'source': 'discord', 'who': 'phirenz', 'what': '<@1320924779556900984> please rebuild PR 14724', 'type': 'command_message'}
2026-07-12T04:28:22.433272	{'source': 'discord', 'who': 'phirenz', 'what': '<@1320924779556900984> please rebuild #14724', 'type': 'command_message'}
2026-07-11T07:56:22.648473	{'source': 'discord', 'who': 'josjuice', 'what': '<@1320924779556900984> please rebuild 14652', 'type': 'command_message'}
2026-07-11T00:13:46.689081	{'source': 'discord', 'who': 'joshuavandaele', 'what': '<@1320924779556900984> please rebuild 14436', 'type': 'command_message'}
2026-07-10T16:19:00.277598	{'source': 'discord', 'who': 'josjuice', 'what': '<@1320924779556900984> please rebuild 14436', 'type': 'command_message'}
2026-07-10T04:54:46.144452	{'source': 'discord', 'who': 'smasher2', 'what': '<@1320924779556900984> please rebuild 14436', 'type': 'command_message'}

Recent 'dev_wark' events

2026-07-18T02:39:47.246508	{'source': 'discord', 'accepted': True, 'type': 'dev_wark'}
2026-07-17T00:44:12.110212	{'source': 'discord', 'accepted': True, 'type': 'dev_wark'}
2026-07-15T19:11:54.747329	{'source': 'discord', 'accepted': True, 'type': 'dev_wark'}
2026-07-12T05:14:19.935387	{'source': 'discord', 'accepted': True, 'type': 'dev_wark'}
2026-07-12T04:30:26.557629	{'source': 'discord', 'accepted': True, 'type': 'dev_wark'}
2026-07-12T04:28:22.433309	{'source': 'discord', 'accepted': True, 'type': 'dev_wark'}

Recent 'gh_issue_comment' events

2026-07-18T23:41:40.251674	{'source': 'ghhookparser', 'repo': 'dolphin-emu/dolphin', 'author': 'thethiny', 'action': 'created', 'id': 14731, 'title': 'Convert To WBFS Support', 'url': 'https://github.com/dolphin-emu/dolphin/pull/14731#issuecomment-5013376425', 'safe_author': False, 'body': "> I'm not sure about NKitHeader. Certainly better, and probably good enough to merge. But it now feels a little bloated, violates DRY.\r\n> \r\n> Maybe the flags would be better handled with `Common::BitStruct`? And some kind of template approach might be better for the Optional fields.\r\n\r\nThe question here would be, do we lose clarity for DRY? Because we are able to compact the 5 structs into a template but then ReadField hides the bounds check and memcpy behind a generic function, making it less immediately obvious what's happening at each step. Let me know which approach to take, meanwhile I will be implementing your changes.", 'raw': {'action': 'created', 'issue': {'url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/14731', 'repository_url': 'https://api.github.com/repos/dolphin-emu/dolphin', 'labels_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/14731/labels{/name}', 'comments_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/14731/comments', 'events_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/14731/events', 'html_url': 'https://github.com/dolphin-emu/dolphin/pull/14731', 'id': 4888393904, 'node_id': 'PR_kwDOALCn2M7x0I-2', 'number': 14731, 'title': 'Convert To WBFS Support', 'user': {'login': 'thethiny', 'id': 6018214, 'node_id': 'MDQ6VXNlcjYwMTgyMTQ=', 'avatar_url': 'https://avatars.githubusercontent.com/u/6018214?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/thethiny', 'html_url': 'https://github.com/thethiny', 'followers_url': 'https://api.github.com/users/thethiny/followers', 'following_url': 'https://api.github.com/users/thethiny/following{/other_user}', 'gists_url': 'https://api.github.com/users/thethiny/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/thethiny/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/thethiny/subscriptions', 'organizations_url': 'https://api.github.com/users/thethiny/orgs', 'repos_url': 'https://api.github.com/users/thethiny/repos', 'events_url': 'https://api.github.com/users/thethiny/events{/privacy}', 'received_events_url': 'https://api.github.com/users/thethiny/received_events', 'type': 'User', 'user_view_type': 'public', 'site_admin': False}, 'labels': [], 'state': 'open', 'locked': False, 'assignees': [], 'milestone': None, 'comments': 43, 'created_at': '2026-07-15T01:16:25Z', 'updated_at': '2026-07-18T23:41:38Z', 'closed_at': None, 'assignee': None, 'author_association': 'NONE', 'issue_field_values': [], 'type': None, 'active_lock_reason': None, 'draft': False, 'pull_request': {'url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/14731', 'html_url': 'https://github.com/dolphin-emu/dolphin/pull/14731', 'diff_url': 'https://github.com/dolphin-emu/dolphin/pull/14731.diff', 'patch_url': 'https://github.com/dolphin-emu/dolphin/pull/14731.patch', 'merged_at': None}, 'body': "This PR introduces Conversion **to** WBFS support. WBFS is the format that is used by USB Loaders on a real Wii device.\r\n\r\n## Design decisions & hardcoded values\r\nThe writer uses fixed sector sizes that match what [libwbfs (the reference implementation by kwiirk)](https://github.com/kwiirk/wbfs/blob/master/libwbfs/libwbfs.c#L128-L134) computes for a standard single-layer Wii disc. These 2 hardcodes are stable and work correctly across all my testings.\r\n- HD sector shift: 9 (512 bytes)\r\n- WBFS sector shift: 21 (2 MiB)\r\nThese are not configurable via the UI. All existing WBFS tools use these values, and since the aim is to support USB Loaders then this has been tested and it is working on a real Wii.\r\n\r\nConverting from WBFS is not enabled. The existing `WbfsFileReader` reports `DataSizeType::UpperBound`, and `ShouldAllowConversion()` requires `Accurate`. I am able to support this but since it was hardcoded by the Dolphin team I thought a discussion is warranted.\r\n\r\n## Testing\r\n- Verified with DolphinTool header and DolphinTool verify\r\n- Verified with wit FILETYPE and wit DUMP (Wiimm's ISO Tools recognizes valid WBFS structure, partitions, encryption)\r\n- Tested ISO to WBFS and RVZ to WBFS conversions\r\n- Output file sizes match Wii Backup Manager when scrubbing is enabled (~0.1% difference), works when scrubbing is disabled.\r\n- Output WBFS files play correctly in Dolphin\r\n- Output WBFS files play correctly on a real Wii using USB Loader GX e25c4f3\r\n", 'reactions': {'url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/14731/reactions', 'total_count': 2, '+1': 2, '-1': 0, 'laugh': 0, 'hooray': 0, 'confused': 0, 'heart': 0, 'rocket': 0, 'eyes': 0}, 'timeline_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/14731/timeline', 'performed_via_github_app': None, 'state_reason': None}, 'comment': {'url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/comments/5013376425', 'html_url': 'https://github.com/dolphin-emu/dolphin/pull/14731#issuecomment-5013376425', 'issue_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/14731', 'id': 5013376425, 'node_id': 'IC_kwDOALCn2M8AAAABKtINqQ', 'user': {'login': 'thethiny', 'id': 6018214, 'node_id': 'MDQ6VXNlcjYwMTgyMTQ=', 'avatar_url': 'https://avatars.githubusercontent.com/u/6018214?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/thethiny', 'html_url': 'https://github.com/thethiny', 'followers_url': 'https://api.github.com/users/thethiny/followers', 'following_url': 'https://api.github.com/users/thethiny/following{/other_user}', 'gists_url': 'https://api.github.com/users/thethiny/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/thethiny/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/thethiny/subscriptions', 'organizations_url': 'https://api.github.com/users/thethiny/orgs', 'repos_url': 'https://api.github.com/users/thethiny/repos', 'events_url': 'https://api.github.com/users/thethiny/events{/privacy}', 'received_events_url': 'https://api.github.com/users/thethiny/received_events', 'type': 'User', 'user_view_type': 'public', 'site_admin': False}, 'created_at': '2026-07-18T23:41:38Z', 'updated_at': '2026-07-18T23:41:38Z', 'body': "> I'm not sure about NKitHeader. Certainly better, and probably good enough to merge. But it now feels a little bloated, violates DRY.\r\n> \r\n> Maybe the flags would be better handled with `Common::BitStruct`? And some kind of template approach might be better for the Optional fields.\r\n\r\nThe question here would be, do we lose clarity for DRY? Because we are able to compact the 5 structs into a template but then ReadField hides the bounds check and memcpy behind a generic function, making it less immediately obvious what's happening at each step. Let me know which approach to take, meanwhile I will be implementing your changes.", 'author_association': 'NONE', 'reactions': {'url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/comments/5013376425/reactions', 'total_count': 0, '+1': 0, '-1': 0, 'laugh': 0, 'hooray': 0, 'confused': 0, 'heart': 0, 'rocket': 0, 'eyes': 0}, 'performed_via_github_app': None, 'minimized': None}, 'repository': {'id': 11577304, 'node_id': 'MDEwOlJlcG9zaXRvcnkxMTU3NzMwNA==', 'name': 'dolphin', 'full_name': 'dolphin-emu/dolphin', 'private': False, 'owner': {'login': 'dolphin-emu', 'id': 5050316, 'node_id': 'MDEyOk9yZ2FuaXphdGlvbjUwNTAzMTY=', 'avatar_url': 'https://avatars.githubusercontent.com/u/5050316?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/dolphin-emu', 'html_url': 'https://github.com/dolphin-emu', 'followers_url': 'https://api.github.com/users/dolphin-emu/followers', 'following_url': 'https://api.github.com/users/dolphin-emu/following{/other_user}', 'gists_url': 'https://api.github.com/users/dolphin-emu/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/dolphin-emu/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/dolphin-emu/subscriptions', 'organizations_url': 'https://api.github.com/users/dolphin-emu/orgs', 'repos_url': 'https://api.github.com/users/dolphin-emu/repos', 'events_url': 'https://api.github.com/users/dolphin-emu/events{/privacy}', 'received_events_url': 'https://api.github.com/users/dolphin-emu/received_events', 'type': 'Organization', 'user_view_type': 'public', 'site_admin': False}, 'html_url': 'https://github.com/dolphin-emu/dolphin', 'description': 'Dolphin is a GameCube / Wii emulator, allowing you to play games for these two platforms on PC with improvements.', 'fork': False, 'url': 'https://api.github.com/repos/dolphin-emu/dolphin', 'forks_url': 'https://api.github.com/repos/dolphin-emu/dolphin/forks', 'keys_url': 'https://api.github.com/repos/dolphin-emu/dolphin/keys{/key_id}', 'collaborators_url': 'https://api.github.com/repos/dolphin-emu/dolphin/collaborators{/collaborator}', 'teams_url': 'https://api.github.com/repos/dolphin-emu/dolphin/teams', 'hooks_url': 'https://api.github.com/repos/dolphin-emu/dolphin/hooks', 'issue_events_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/events{/number}', 'events_url': 'https://api.github.com/repos/dolphin-emu/dolphin/events', 'assignees_url': 'https://api.github.com/repos/dolphin-emu/dolphin/assignees{/user}', 'branches_url': 'https://api.github.com/repos/dolphin-emu/dolphin/branches{/branch}', 'tags_url': 'https://api.github.com/repos/dolphin-emu/dolphin/tags', 'blobs_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/blobs{/sha}', 'git_tags_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/tags{/sha}', 'git_refs_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/refs{/sha}', 'trees_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/trees{/sha}', 'statuses_url': 'https://api.github.com/repos/dolphin-emu/dolphin/statuses/{sha}', 'languages_url': 'https://api.github.com/repos/dolphin-emu/dolphin/languages', 'stargazers_url': 'https://api.github.com/repos/dolphin-emu/dolphin/stargazers', 'contributors_url': 'https://api.github.com/repos/dolphin-emu/dolphin/contributors', 'subscribers_url': 'https://api.github.com/repos/dolphin-emu/dolphin/subscribers', 'subscription_url': 'https://api.github.com/repos/dolphin-emu/dolphin/subscription', 'commits_url': 'https://api.github.com/repos/dolphin-emu/dolphin/commits{/sha}', 'git_commits_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/commits{/sha}', 'comments_url': 'https://api.github.com/repos/dolphin-emu/dolphin/comments{/number}', 'issue_comment_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/comments{/number}', 'contents_url': 'https://api.github.com/repos/dolphin-emu/dolphin/contents/{+path}', 'compare_url': 'https://api.github.com/repos/dolphin-emu/dolphin/compare/{base}...{head}', 'merges_url': 'https://api.github.com/repos/dolphin-emu/dolphin/merges', 'archive_url': 'https://api.github.com/repos/dolphin-emu/dolphin/{archive_format}{/ref}', 'downloads_url': 'https://api.github.com/repos/dolphin-emu/dolphin/downloads', 'issues_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues{/number}', 'pulls_url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls{/number}', 'milestones_url': 'https://api.github.com/repos/dolphin-emu/dolphin/milestones{/number}', 'notifications_url': 'https://api.github.com/repos/dolphin-emu/dolphin/notifications{?since,all,participating}', 'labels_url': 'https://api.github.com/repos/dolphin-emu/dolphin/labels{/name}', 'releases_url': 'https://api.github.com/repos/dolphin-emu/dolphin/releases{/id}', 'deployments_url': 'https://api.github.com/repos/dolphin-emu/dolphin/deployments', 'created_at': '2013-07-22T09:07:57Z', 'updated_at': '2026-07-18T23:13:54Z', 'pushed_at': '2026-07-18T10:34:54Z', 'git_url': 'git://github.com/dolphin-emu/dolphin.git', 'ssh_url': 'git@github.com:dolphin-emu/dolphin.git', 'clone_url': 'https://github.com/dolphin-emu/dolphin.git', 'svn_url': 'https://github.com/dolphin-emu/dolphin', 'homepage': 'https://dolphin-emu.org', 'size': 558448, 'stargazers_count': 15273, 'watchers_count': 15273, 'language': 'C++', 'has_issues': False, 'has_projects': False, 'has_downloads': True, 'has_wiki': True, 'has_pages': False, 'has_discussions': False, 'forks_count': 3162, 'mirror_url': None, 'archived': False, 'disabled': False, 'open_issues_count': 446, 'license': {'key': 'other', 'name': 'Other', 'spdx_id': 'NOASSERTION', 'url': None, 'node_id': 'MDc6TGljZW5zZTA='}, 'allow_forking': True, 'is_template': False, 'web_commit_signoff_required': False, 'has_pull_requests': True, 'pull_request_creation_policy': 'all', 'topics': ['cpp', 'emulation', 'emulator', 'gamecube', 'wii'], 'visibility': 'public', 'forks': 3162, 'open_issues': 446, 'watchers': 15273, 'default_branch': 'master', 'custom_properties': {}}, 'organization': {'login': 'dolphin-emu', 'id': 5050316, 'node_id': 'MDEyOk9yZ2FuaXphdGlvbjUwNTAzMTY=', 'url': 'https://api.github.com/orgs/dolphin-emu', 'repos_url': 'https://api.github.com/orgs/dolphin-emu/repos', 'events_url': 'https://api.github.com/orgs/dolphin-emu/events', 'hooks_url': 'https://api.github.com/orgs/dolphin-emu/hooks', 'issues_url': 'https://api.github.com/orgs/dolphin-emu/issues', 'members_url': 'https://api.github.com/orgs/dolphin-emu/members{/member}', 'public_members_url': 'https://api.github.com/orgs/dolphin-emu/public_members{/member}', 'avatar_url': 'https://avatars.githubusercontent.com/u/5050316?v=4', 'description': ''}, 'sender': {'login': 'thethiny', 'id': 6018214, 'node_id': 'MDQ6VXNlcjYwMTgyMTQ=', 'avatar_url': 'https://avatars.githubusercontent.com/u/6018214?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/thethiny', 'html_url': 'https://github.com/thethiny', 'followers_url': 'https://api.github.com/users/thethiny/followers', 'following_url': 'https://api.github.com/users/thethiny/following{/other_user}', 'gists_url': 'https://api.github.com/users/thethiny/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/thethiny/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/thethiny/subscriptions', 'organizations_url': 'https://api.github.com/users/thethiny/orgs', 'repos_url': 'https://api.github.com/users/thethiny/repos', 'events_url': 'https://api.github.com/users/thethiny/events{/privacy}', 'received_events_url': 'https://api.github.com/users/thethiny/received_events', 'type': 'User', 'user_view_type': 'public', 'site_admin': False}, 'installation': {'id': 35437981, 'node_id': 'MDIzOkludGVncmF0aW9uSW5zdGFsbGF0aW9uMzU0Mzc5ODE='}}, 'type': 'gh_issue_comment'}
2026-07-18T22:41:10.191011	{'source': 'ghhookparser', 'repo': 'dolphin-emu/sadm', 'author': 'phire', 'action': 'created', 'id': 204, 'title': 'Update buildbot configuration to use new CMake presets', 'url': 'https://github.com/dolphin-emu/sadm/pull/204#issuecomment-5013205285', 'safe_author': True, 'body': "So, my only concern is that this wipes out the ability for the builders to build any commits older than PR 14475. \r\n\r\nIt wouldn't be that much effort to keep the old codepath around (though not trivial).\r\n\r\nThe disadvantages of not doing so is that every single open PR will be required to be rebased before it can be merged. They will merge cleanly (as long as they haven't touched any cmake/vs files), but any new commits or manual buildbot runs will fail.\r\n\r\nWhich would result in extra build failure spam in #dev-activity, needing to tell people to rebase, walking git noobs through the process of rebasing, etc. Not the biggest issue, but a little annoying. ", 'raw': {'action': 'created', 'issue': {'url': 'https://api.github.com/repos/dolphin-emu/sadm/issues/204', 'repository_url': 'https://api.github.com/repos/dolphin-emu/sadm', 'labels_url': 'https://api.github.com/repos/dolphin-emu/sadm/issues/204/labels{/name}', 'comments_url': 'https://api.github.com/repos/dolphin-emu/sadm/issues/204/comments', 'events_url': 'https://api.github.com/repos/dolphin-emu/sadm/issues/204/events', 'html_url': 'https://github.com/dolphin-emu/sadm/pull/204', 'id': 4082033094, 'node_id': 'PR_kwDOALAO3s7K5is0', 'number': 204, 'title': 'Update buildbot configuration to use new CMake presets', 'user': {'login': 'JoshuaVandaele', 'id': 24195176, 'node_id': 'MDQ6VXNlcjI0MTk1MTc2', 'avatar_url': 'https://avatars.githubusercontent.com/u/24195176?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/JoshuaVandaele', 'html_url': 'https://github.com/JoshuaVandaele', 'followers_url': 'https://api.github.com/users/JoshuaVandaele/followers', 'following_url': 'https://api.github.com/users/JoshuaVandaele/following{/other_user}', 'gists_url': 'https://api.github.com/users/JoshuaVandaele/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/JoshuaVandaele/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/JoshuaVandaele/subscriptions', 'organizations_url': 'https://api.github.com/users/JoshuaVandaele/orgs', 'repos_url': 'https://api.github.com/users/JoshuaVandaele/repos', 'events_url': 'https://api.github.com/users/JoshuaVandaele/events{/privacy}', 'received_events_url': 'https://api.github.com/users/JoshuaVandaele/received_events', 'type': 'User', 'user_view_type': 'public', 'site_admin': False}, 'labels': [], 'state': 'open', 'locked': False, 'assignees': [], 'milestone': None, 'comments': 1, 'created_at': '2026-03-16T11:57:11Z', 'updated_at': '2026-07-18T22:41:08Z', 'closed_at': None, 'assignee': None, 'author_association': 'NONE', 'issue_field_values': [], 'type': None, 'active_lock_reason': None, 'draft': False, 'pull_request': {'url': 'https://api.github.com/repos/dolphin-emu/sadm/pulls/204', 'html_url': 'https://github.com/dolphin-emu/sadm/pull/204', 'diff_url': 'https://github.com/dolphin-emu/sadm/pull/204.diff', 'patch_url': 'https://github.com/dolphin-emu/sadm/pull/204.patch', 'merged_at': None}, 'body': 'From https://github.com/dolphin-emu/dolphin/pull/14475', 'reactions': {'url': 'https://api.github.com/repos/dolphin-emu/sadm/issues/204/reactions', 'total_count': 0, '+1': 0, '-1': 0, 'laugh': 0, 'hooray': 0, 'confused': 0, 'heart': 0, 'rocket': 0, 'eyes': 0}, 'timeline_url': 'https://api.github.com/repos/dolphin-emu/sadm/issues/204/timeline', 'performed_via_github_app': None, 'state_reason': None}, 'comment': {'url': 'https://api.github.com/repos/dolphin-emu/sadm/issues/comments/5013205285', 'html_url': 'https://github.com/dolphin-emu/sadm/pull/204#issuecomment-5013205285', 'issue_url': 'https://api.github.com/repos/dolphin-emu/sadm/issues/204', 'id': 5013205285, 'node_id': 'IC_kwDOALAO3s8AAAABKs9xJQ', 'user': {'login': 'phire', 'id': 138484, 'node_id': 'MDQ6VXNlcjEzODQ4NA==', 'avatar_url': 'https://avatars.githubusercontent.com/u/138484?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/phire', 'html_url': 'https://github.com/phire', 'followers_url': 'https://api.github.com/users/phire/followers', 'following_url': 'https://api.github.com/users/phire/following{/other_user}', 'gists_url': 'https://api.github.com/users/phire/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/phire/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/phire/subscriptions', 'organizations_url': 'https://api.github.com/users/phire/orgs', 'repos_url': 'https://api.github.com/users/phire/repos', 'events_url': 'https://api.github.com/users/phire/events{/privacy}', 'received_events_url': 'https://api.github.com/users/phire/received_events', 'type': 'User', 'user_view_type': 'public', 'site_admin': False}, 'created_at': '2026-07-18T22:41:08Z', 'updated_at': '2026-07-18T22:41:08Z', 'body': "So, my only concern is that this wipes out the ability for the builders to build any commits older than PR 14475. \r\n\r\nIt wouldn't be that much effort to keep the old codepath around (though not trivial).\r\n\r\nThe disadvantages of not doing so is that every single open PR will be required to be rebased before it can be merged. They will merge cleanly (as long as they haven't touched any cmake/vs files), but any new commits or manual buildbot runs will fail.\r\n\r\nWhich would result in extra build failure spam in #dev-activity, needing to tell people to rebase, walking git noobs through the process of rebasing, etc. Not the biggest issue, but a little annoying. ", 'author_association': 'MEMBER', 'reactions': {'url': 'https://api.github.com/repos/dolphin-emu/sadm/issues/comments/5013205285/reactions', 'total_count': 0, '+1': 0, '-1': 0, 'laugh': 0, 'hooray': 0, 'confused': 0, 'heart': 0, 'rocket': 0, 'eyes': 0}, 'performed_via_github_app': None, 'minimized': None}, 'repository': {'id': 11538142, 'node_id': 'MDEwOlJlcG9zaXRvcnkxMTUzODE0Mg==', 'name': 'sadm', 'full_name': 'dolphin-emu/sadm', 'private': False, 'owner': {'login': 'dolphin-emu', 'id': 5050316, 'node_id': 'MDEyOk9yZ2FuaXphdGlvbjUwNTAzMTY=', 'avatar_url': 'https://avatars.githubusercontent.com/u/5050316?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/dolphin-emu', 'html_url': 'https://github.com/dolphin-emu', 'followers_url': 'https://api.github.com/users/dolphin-emu/followers', 'following_url': 'https://api.github.com/users/dolphin-emu/following{/other_user}', 'gists_url': 'https://api.github.com/users/dolphin-emu/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/dolphin-emu/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/dolphin-emu/subscriptions', 'organizations_url': 'https://api.github.com/users/dolphin-emu/orgs', 'repos_url': 'https://api.github.com/users/dolphin-emu/repos', 'events_url': 'https://api.github.com/users/dolphin-emu/events{/privacy}', 'received_events_url': 'https://api.github.com/users/dolphin-emu/received_events', 'type': 'Organization', 'user_view_type': 'public', 'site_admin': False}, 'html_url': 'https://github.com/dolphin-emu/sadm', 'description': 'Scripts and configurations for the Dolphin Emulator infrastructure', 'fork': False, 'url': 'https://api.github.com/repos/dolphin-emu/sadm', 'forks_url': 'https://api.github.com/repos/dolphin-emu/sadm/forks', 'keys_url': 'https://api.github.com/repos/dolphin-emu/sadm/keys{/key_id}', 'collaborators_url': 'https://api.github.com/repos/dolphin-emu/sadm/collaborators{/collaborator}', 'teams_url': 'https://api.github.com/repos/dolphin-emu/sadm/teams', 'hooks_url': 'https://api.github.com/repos/dolphin-emu/sadm/hooks', 'issue_events_url': 'https://api.github.com/repos/dolphin-emu/sadm/issues/events{/number}', 'events_url': 'https://api.github.com/repos/dolphin-emu/sadm/events', 'assignees_url': 'https://api.github.com/repos/dolphin-emu/sadm/assignees{/user}', 'branches_url': 'https://api.github.com/repos/dolphin-emu/sadm/branches{/branch}', 'tags_url': 'https://api.github.com/repos/dolphin-emu/sadm/tags', 'blobs_url': 'https://api.github.com/repos/dolphin-emu/sadm/git/blobs{/sha}', 'git_tags_url': 'https://api.github.com/repos/dolphin-emu/sadm/git/tags{/sha}', 'git_refs_url': 'https://api.github.com/repos/dolphin-emu/sadm/git/refs{/sha}', 'trees_url': 'https://api.github.com/repos/dolphin-emu/sadm/git/trees{/sha}', 'statuses_url': 'https://api.github.com/repos/dolphin-emu/sadm/statuses/{sha}', 'languages_url': 'https://api.github.com/repos/dolphin-emu/sadm/languages', 'stargazers_url': 'https://api.github.com/repos/dolphin-emu/sadm/stargazers', 'contributors_url': 'https://api.github.com/repos/dolphin-emu/sadm/contributors', 'subscribers_url': 'https://api.github.com/repos/dolphin-emu/sadm/subscribers', 'subscription_url': 'https://api.github.com/repos/dolphin-emu/sadm/subscription', 'commits_url': 'https://api.github.com/repos/dolphin-emu/sadm/commits{/sha}', 'git_commits_url': 'https://api.github.com/repos/dolphin-emu/sadm/git/commits{/sha}', 'comments_url': 'https://api.github.com/repos/dolphin-emu/sadm/comments{/number}', 'issue_comment_url': 'https://api.github.com/repos/dolphin-emu/sadm/issues/comments{/number}', 'contents_url': 'https://api.github.com/repos/dolphin-emu/sadm/contents/{+path}', 'compare_url': 'https://api.github.com/repos/dolphin-emu/sadm/compare/{base}...{head}', 'merges_url': 'https://api.github.com/repos/dolphin-emu/sadm/merges', 'archive_url': 'https://api.github.com/repos/dolphin-emu/sadm/{archive_format}{/ref}', 'downloads_url': 'https://api.github.com/repos/dolphin-emu/sadm/downloads', 'issues_url': 'https://api.github.com/repos/dolphin-emu/sadm/issues{/number}', 'pulls_url': 'https://api.github.com/repos/dolphin-emu/sadm/pulls{/number}', 'milestones_url': 'https://api.github.com/repos/dolphin-emu/sadm/milestones{/number}', 'notifications_url': 'https://api.github.com/repos/dolphin-emu/sadm/notifications{?since,all,participating}', 'labels_url': 'https://api.github.com/repos/dolphin-emu/sadm/labels{/name}', 'releases_url': 'https://api.github.com/repos/dolphin-emu/sadm/releases{/id}', 'deployments_url': 'https://api.github.com/repos/dolphin-emu/sadm/deployments', 'created_at': '2013-07-19T22:07:05Z', 'updated_at': '2026-07-10T05:00:46Z', 'pushed_at': '2026-07-10T05:00:33Z', 'git_url': 'git://github.com/dolphin-emu/sadm.git', 'ssh_url': 'git@github.com:dolphin-emu/sadm.git', 'clone_url': 'https://github.com/dolphin-emu/sadm.git', 'svn_url': 'https://github.com/dolphin-emu/sadm', 'homepage': '', 'size': 1235, 'stargazers_count': 51, 'watchers_count': 51, 'language': 'Nix', 'has_issues': True, 'has_projects': False, 'has_downloads': True, 'has_wiki': True, 'has_pages': False, 'has_discussions': False, 'forks_count': 43, 'mirror_url': None, 'archived': False, 'disabled': False, 'open_issues_count': 4, 'license': {'key': 'mit', 'name': 'MIT License', 'spdx_id': 'MIT', 'url': 'https://api.github.com/licenses/mit', 'node_id': 'MDc6TGljZW5zZTEz'}, 'allow_forking': True, 'is_template': False, 'web_commit_signoff_required': False, 'has_pull_requests': True, 'pull_request_creation_policy': 'all', 'topics': [], 'visibility': 'public', 'forks': 43, 'open_issues': 4, 'watchers': 51, 'default_branch': 'master', 'custom_properties': {}}, 'organization': {'login': 'dolphin-emu', 'id': 5050316, 'node_id': 'MDEyOk9yZ2FuaXphdGlvbjUwNTAzMTY=', 'url': 'https://api.github.com/orgs/dolphin-emu', 'repos_url': 'https://api.github.com/orgs/dolphin-emu/repos', 'events_url': 'https://api.github.com/orgs/dolphin-emu/events', 'hooks_url': 'https://api.github.com/orgs/dolphin-emu/hooks', 'issues_url': 'https://api.github.com/orgs/dolphin-emu/issues', 'members_url': 'https://api.github.com/orgs/dolphin-emu/members{/member}', 'public_members_url': 'https://api.github.com/orgs/dolphin-emu/public_members{/member}', 'avatar_url': 'https://avatars.githubusercontent.com/u/5050316?v=4', 'description': ''}, 'sender': {'login': 'phire', 'id': 138484, 'node_id': 'MDQ6VXNlcjEzODQ4NA==', 'avatar_url': 'https://avatars.githubusercontent.com/u/138484?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/phire', 'html_url': 'https://github.com/phire', 'followers_url': 'https://api.github.com/users/phire/followers', 'following_url': 'https://api.github.com/users/phire/following{/other_user}', 'gists_url': 'https://api.github.com/users/phire/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/phire/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/phire/subscriptions', 'organizations_url': 'https://api.github.com/users/phire/orgs', 'repos_url': 'https://api.github.com/users/phire/repos', 'events_url': 'https://api.github.com/users/phire/events{/privacy}', 'received_events_url': 'https://api.github.com/users/phire/received_events', 'type': 'User', 'user_view_type': 'public', 'site_admin': False}, 'installation': {'id': 35437981, 'node_id': 'MDIzOkludGVncmF0aW9uSW5zdGFsbGF0aW9uMzU0Mzc5ODE='}}, 'type': 'gh_issue_comment'}
2026-07-18T22:17:00.816191	{'source': 'ghhookparser', 'repo': 'dolphin-emu/dolphin', 'author': 'JoshuaVandaele', 'action': 'created', 'id': 14731, 'title': 'Convert To WBFS Support', 'url': 'https://github.com/dolphin-emu/dolphin/pull/14731#issuecomment-5013135939', 'safe_author': True, 'body': "> The build failures seem CMake related but I'm sure that I did it right so idk why it's failing\r\n\r\nWindows doesn't use CMake ([yet](https://github.com/dolphin-emu/dolphin/pull/14475)), but instead Visual Studio project files to build", 'raw': {'action': 'created', 'issue': {'url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/14731', 'repository_url': 'https://api.github.com/repos/dolphin-emu/dolphin', 'labels_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/14731/labels{/name}', 'comments_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/14731/comments', 'events_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/14731/events', 'html_url': 'https://github.com/dolphin-emu/dolphin/pull/14731', 'id': 4888393904, 'node_id': 'PR_kwDOALCn2M7x0I-2', 'number': 14731, 'title': 'Convert To WBFS Support', 'user': {'login': 'thethiny', 'id': 6018214, 'node_id': 'MDQ6VXNlcjYwMTgyMTQ=', 'avatar_url': 'https://avatars.githubusercontent.com/u/6018214?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/thethiny', 'html_url': 'https://github.com/thethiny', 'followers_url': 'https://api.github.com/users/thethiny/followers', 'following_url': 'https://api.github.com/users/thethiny/following{/other_user}', 'gists_url': 'https://api.github.com/users/thethiny/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/thethiny/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/thethiny/subscriptions', 'organizations_url': 'https://api.github.com/users/thethiny/orgs', 'repos_url': 'https://api.github.com/users/thethiny/repos', 'events_url': 'https://api.github.com/users/thethiny/events{/privacy}', 'received_events_url': 'https://api.github.com/users/thethiny/received_events', 'type': 'User', 'user_view_type': 'public', 'site_admin': False}, 'labels': [], 'state': 'open', 'locked': False, 'assignees': [], 'milestone': None, 'comments': 42, 'created_at': '2026-07-15T01:16:25Z', 'updated_at': '2026-07-18T22:16:59Z', 'closed_at': None, 'assignee': None, 'author_association': 'NONE', 'issue_field_values': [], 'type': None, 'active_lock_reason': None, 'draft': False, 'pull_request': {'url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/14731', 'html_url': 'https://github.com/dolphin-emu/dolphin/pull/14731', 'diff_url': 'https://github.com/dolphin-emu/dolphin/pull/14731.diff', 'patch_url': 'https://github.com/dolphin-emu/dolphin/pull/14731.patch', 'merged_at': None}, 'body': "This PR introduces Conversion **to** WBFS support. WBFS is the format that is used by USB Loaders on a real Wii device.\r\n\r\n## Design decisions & hardcoded values\r\nThe writer uses fixed sector sizes that match what [libwbfs (the reference implementation by kwiirk)](https://github.com/kwiirk/wbfs/blob/master/libwbfs/libwbfs.c#L128-L134) computes for a standard single-layer Wii disc. These 2 hardcodes are stable and work correctly across all my testings.\r\n- HD sector shift: 9 (512 bytes)\r\n- WBFS sector shift: 21 (2 MiB)\r\nThese are not configurable via the UI. All existing WBFS tools use these values, and since the aim is to support USB Loaders then this has been tested and it is working on a real Wii.\r\n\r\nConverting from WBFS is not enabled. The existing `WbfsFileReader` reports `DataSizeType::UpperBound`, and `ShouldAllowConversion()` requires `Accurate`. I am able to support this but since it was hardcoded by the Dolphin team I thought a discussion is warranted.\r\n\r\n## Testing\r\n- Verified with DolphinTool header and DolphinTool verify\r\n- Verified with wit FILETYPE and wit DUMP (Wiimm's ISO Tools recognizes valid WBFS structure, partitions, encryption)\r\n- Tested ISO to WBFS and RVZ to WBFS conversions\r\n- Output file sizes match Wii Backup Manager when scrubbing is enabled (~0.1% difference), works when scrubbing is disabled.\r\n- Output WBFS files play correctly in Dolphin\r\n- Output WBFS files play correctly on a real Wii using USB Loader GX e25c4f3\r\n", 'reactions': {'url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/14731/reactions', 'total_count': 2, '+1': 2, '-1': 0, 'laugh': 0, 'hooray': 0, 'confused': 0, 'heart': 0, 'rocket': 0, 'eyes': 0}, 'timeline_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/14731/timeline', 'performed_via_github_app': None, 'state_reason': None}, 'comment': {'url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/comments/5013135939', 'html_url': 'https://github.com/dolphin-emu/dolphin/pull/14731#issuecomment-5013135939', 'issue_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/14731', 'id': 5013135939, 'node_id': 'IC_kwDOALCn2M8AAAABKs5iQw', 'user': {'login': 'JoshuaVandaele', 'id': 24195176, 'node_id': 'MDQ6VXNlcjI0MTk1MTc2', 'avatar_url': 'https://avatars.githubusercontent.com/u/24195176?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/JoshuaVandaele', 'html_url': 'https://github.com/JoshuaVandaele', 'followers_url': 'https://api.github.com/users/JoshuaVandaele/followers', 'following_url': 'https://api.github.com/users/JoshuaVandaele/following{/other_user}', 'gists_url': 'https://api.github.com/users/JoshuaVandaele/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/JoshuaVandaele/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/JoshuaVandaele/subscriptions', 'organizations_url': 'https://api.github.com/users/JoshuaVandaele/orgs', 'repos_url': 'https://api.github.com/users/JoshuaVandaele/repos', 'events_url': 'https://api.github.com/users/JoshuaVandaele/events{/privacy}', 'received_events_url': 'https://api.github.com/users/JoshuaVandaele/received_events', 'type': 'User', 'user_view_type': 'public', 'site_admin': False}, 'created_at': '2026-07-18T22:16:59Z', 'updated_at': '2026-07-18T22:16:59Z', 'body': "> The build failures seem CMake related but I'm sure that I did it right so idk why it's failing\r\n\r\nWindows doesn't use CMake ([yet](https://github.com/dolphin-emu/dolphin/pull/14475)), but instead Visual Studio project files to build", 'author_association': 'MEMBER', 'reactions': {'url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/comments/5013135939/reactions', 'total_count': 0, '+1': 0, '-1': 0, 'laugh': 0, 'hooray': 0, 'confused': 0, 'heart': 0, 'rocket': 0, 'eyes': 0}, 'performed_via_github_app': None, 'minimized': None}, 'repository': {'id': 11577304, 'node_id': 'MDEwOlJlcG9zaXRvcnkxMTU3NzMwNA==', 'name': 'dolphin', 'full_name': 'dolphin-emu/dolphin', 'private': False, 'owner': {'login': 'dolphin-emu', 'id': 5050316, 'node_id': 'MDEyOk9yZ2FuaXphdGlvbjUwNTAzMTY=', 'avatar_url': 'https://avatars.githubusercontent.com/u/5050316?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/dolphin-emu', 'html_url': 'https://github.com/dolphin-emu', 'followers_url': 'https://api.github.com/users/dolphin-emu/followers', 'following_url': 'https://api.github.com/users/dolphin-emu/following{/other_user}', 'gists_url': 'https://api.github.com/users/dolphin-emu/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/dolphin-emu/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/dolphin-emu/subscriptions', 'organizations_url': 'https://api.github.com/users/dolphin-emu/orgs', 'repos_url': 'https://api.github.com/users/dolphin-emu/repos', 'events_url': 'https://api.github.com/users/dolphin-emu/events{/privacy}', 'received_events_url': 'https://api.github.com/users/dolphin-emu/received_events', 'type': 'Organization', 'user_view_type': 'public', 'site_admin': False}, 'html_url': 'https://github.com/dolphin-emu/dolphin', 'description': 'Dolphin is a GameCube / Wii emulator, allowing you to play games for these two platforms on PC with improvements.', 'fork': False, 'url': 'https://api.github.com/repos/dolphin-emu/dolphin', 'forks_url': 'https://api.github.com/repos/dolphin-emu/dolphin/forks', 'keys_url': 'https://api.github.com/repos/dolphin-emu/dolphin/keys{/key_id}', 'collaborators_url': 'https://api.github.com/repos/dolphin-emu/dolphin/collaborators{/collaborator}', 'teams_url': 'https://api.github.com/repos/dolphin-emu/dolphin/teams', 'hooks_url': 'https://api.github.com/repos/dolphin-emu/dolphin/hooks', 'issue_events_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/events{/number}', 'events_url': 'https://api.github.com/repos/dolphin-emu/dolphin/events', 'assignees_url': 'https://api.github.com/repos/dolphin-emu/dolphin/assignees{/user}', 'branches_url': 'https://api.github.com/repos/dolphin-emu/dolphin/branches{/branch}', 'tags_url': 'https://api.github.com/repos/dolphin-emu/dolphin/tags', 'blobs_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/blobs{/sha}', 'git_tags_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/tags{/sha}', 'git_refs_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/refs{/sha}', 'trees_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/trees{/sha}', 'statuses_url': 'https://api.github.com/repos/dolphin-emu/dolphin/statuses/{sha}', 'languages_url': 'https://api.github.com/repos/dolphin-emu/dolphin/languages', 'stargazers_url': 'https://api.github.com/repos/dolphin-emu/dolphin/stargazers', 'contributors_url': 'https://api.github.com/repos/dolphin-emu/dolphin/contributors', 'subscribers_url': 'https://api.github.com/repos/dolphin-emu/dolphin/subscribers', 'subscription_url': 'https://api.github.com/repos/dolphin-emu/dolphin/subscription', 'commits_url': 'https://api.github.com/repos/dolphin-emu/dolphin/commits{/sha}', 'git_commits_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/commits{/sha}', 'comments_url': 'https://api.github.com/repos/dolphin-emu/dolphin/comments{/number}', 'issue_comment_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/comments{/number}', 'contents_url': 'https://api.github.com/repos/dolphin-emu/dolphin/contents/{+path}', 'compare_url': 'https://api.github.com/repos/dolphin-emu/dolphin/compare/{base}...{head}', 'merges_url': 'https://api.github.com/repos/dolphin-emu/dolphin/merges', 'archive_url': 'https://api.github.com/repos/dolphin-emu/dolphin/{archive_format}{/ref}', 'downloads_url': 'https://api.github.com/repos/dolphin-emu/dolphin/downloads', 'issues_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues{/number}', 'pulls_url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls{/number}', 'milestones_url': 'https://api.github.com/repos/dolphin-emu/dolphin/milestones{/number}', 'notifications_url': 'https://api.github.com/repos/dolphin-emu/dolphin/notifications{?since,all,participating}', 'labels_url': 'https://api.github.com/repos/dolphin-emu/dolphin/labels{/name}', 'releases_url': 'https://api.github.com/repos/dolphin-emu/dolphin/releases{/id}', 'deployments_url': 'https://api.github.com/repos/dolphin-emu/dolphin/deployments', 'created_at': '2013-07-22T09:07:57Z', 'updated_at': '2026-07-18T18:44:16Z', 'pushed_at': '2026-07-18T10:34:54Z', 'git_url': 'git://github.com/dolphin-emu/dolphin.git', 'ssh_url': 'git@github.com:dolphin-emu/dolphin.git', 'clone_url': 'https://github.com/dolphin-emu/dolphin.git', 'svn_url': 'https://github.com/dolphin-emu/dolphin', 'homepage': 'https://dolphin-emu.org', 'size': 558448, 'stargazers_count': 15272, 'watchers_count': 15272, 'language': 'C++', 'has_issues': False, 'has_projects': False, 'has_downloads': True, 'has_wiki': True, 'has_pages': False, 'has_discussions': False, 'forks_count': 3162, 'mirror_url': None, 'archived': False, 'disabled': False, 'open_issues_count': 446, 'license': {'key': 'other', 'name': 'Other', 'spdx_id': 'NOASSERTION', 'url': None, 'node_id': 'MDc6TGljZW5zZTA='}, 'allow_forking': True, 'is_template': False, 'web_commit_signoff_required': False, 'has_pull_requests': True, 'pull_request_creation_policy': 'all', 'topics': ['cpp', 'emulation', 'emulator', 'gamecube', 'wii'], 'visibility': 'public', 'forks': 3162, 'open_issues': 446, 'watchers': 15272, 'default_branch': 'master', 'custom_properties': {}}, 'organization': {'login': 'dolphin-emu', 'id': 5050316, 'node_id': 'MDEyOk9yZ2FuaXphdGlvbjUwNTAzMTY=', 'url': 'https://api.github.com/orgs/dolphin-emu', 'repos_url': 'https://api.github.com/orgs/dolphin-emu/repos', 'events_url': 'https://api.github.com/orgs/dolphin-emu/events', 'hooks_url': 'https://api.github.com/orgs/dolphin-emu/hooks', 'issues_url': 'https://api.github.com/orgs/dolphin-emu/issues', 'members_url': 'https://api.github.com/orgs/dolphin-emu/members{/member}', 'public_members_url': 'https://api.github.com/orgs/dolphin-emu/public_members{/member}', 'avatar_url': 'https://avatars.githubusercontent.com/u/5050316?v=4', 'description': ''}, 'sender': {'login': 'JoshuaVandaele', 'id': 24195176, 'node_id': 'MDQ6VXNlcjI0MTk1MTc2', 'avatar_url': 'https://avatars.githubusercontent.com/u/24195176?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/JoshuaVandaele', 'html_url': 'https://github.com/JoshuaVandaele', 'followers_url': 'https://api.github.com/users/JoshuaVandaele/followers', 'following_url': 'https://api.github.com/users/JoshuaVandaele/following{/other_user}', 'gists_url': 'https://api.github.com/users/JoshuaVandaele/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/JoshuaVandaele/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/JoshuaVandaele/subscriptions', 'organizations_url': 'https://api.github.com/users/JoshuaVandaele/orgs', 'repos_url': 'https://api.github.com/users/JoshuaVandaele/repos', 'events_url': 'https://api.github.com/users/JoshuaVandaele/events{/privacy}', 'received_events_url': 'https://api.github.com/users/JoshuaVandaele/received_events', 'type': 'User', 'user_view_type': 'public', 'site_admin': False}, 'installation': {'id': 35437981, 'node_id': 'MDIzOkludGVncmF0aW9uSW5zdGFsbGF0aW9uMzU0Mzc5ODE='}}, 'type': 'gh_issue_comment'}
2026-07-18T22:03:31.010767	{'source': 'ghhookparser', 'repo': 'dolphin-emu/dolphin', 'author': 'thethiny', 'action': 'created', 'id': 14731, 'title': 'Convert To WBFS Support', 'url': 'https://github.com/dolphin-emu/dolphin/pull/14731#issuecomment-5013096819', 'safe_author': False, 'body': "The build failures seem CMake related but I'm sure that I did it right so idk why it's failing", 'raw': {'action': 'created', 'issue': {'url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/14731', 'repository_url': 'https://api.github.com/repos/dolphin-emu/dolphin', 'labels_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/14731/labels{/name}', 'comments_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/14731/comments', 'events_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/14731/events', 'html_url': 'https://github.com/dolphin-emu/dolphin/pull/14731', 'id': 4888393904, 'node_id': 'PR_kwDOALCn2M7x0I-2', 'number': 14731, 'title': 'Convert To WBFS Support', 'user': {'login': 'thethiny', 'id': 6018214, 'node_id': 'MDQ6VXNlcjYwMTgyMTQ=', 'avatar_url': 'https://avatars.githubusercontent.com/u/6018214?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/thethiny', 'html_url': 'https://github.com/thethiny', 'followers_url': 'https://api.github.com/users/thethiny/followers', 'following_url': 'https://api.github.com/users/thethiny/following{/other_user}', 'gists_url': 'https://api.github.com/users/thethiny/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/thethiny/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/thethiny/subscriptions', 'organizations_url': 'https://api.github.com/users/thethiny/orgs', 'repos_url': 'https://api.github.com/users/thethiny/repos', 'events_url': 'https://api.github.com/users/thethiny/events{/privacy}', 'received_events_url': 'https://api.github.com/users/thethiny/received_events', 'type': 'User', 'user_view_type': 'public', 'site_admin': False}, 'labels': [], 'state': 'open', 'locked': False, 'assignees': [], 'milestone': None, 'comments': 41, 'created_at': '2026-07-15T01:16:25Z', 'updated_at': '2026-07-18T22:03:28Z', 'closed_at': None, 'assignee': None, 'author_association': 'NONE', 'issue_field_values': [], 'type': None, 'active_lock_reason': None, 'draft': False, 'pull_request': {'url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/14731', 'html_url': 'https://github.com/dolphin-emu/dolphin/pull/14731', 'diff_url': 'https://github.com/dolphin-emu/dolphin/pull/14731.diff', 'patch_url': 'https://github.com/dolphin-emu/dolphin/pull/14731.patch', 'merged_at': None}, 'body': "This PR introduces Conversion **to** WBFS support. WBFS is the format that is used by USB Loaders on a real Wii device.\r\n\r\n## Design decisions & hardcoded values\r\nThe writer uses fixed sector sizes that match what [libwbfs (the reference implementation by kwiirk)](https://github.com/kwiirk/wbfs/blob/master/libwbfs/libwbfs.c#L128-L134) computes for a standard single-layer Wii disc. These 2 hardcodes are stable and work correctly across all my testings.\r\n- HD sector shift: 9 (512 bytes)\r\n- WBFS sector shift: 21 (2 MiB)\r\nThese are not configurable via the UI. All existing WBFS tools use these values, and since the aim is to support USB Loaders then this has been tested and it is working on a real Wii.\r\n\r\nConverting from WBFS is not enabled. The existing `WbfsFileReader` reports `DataSizeType::UpperBound`, and `ShouldAllowConversion()` requires `Accurate`. I am able to support this but since it was hardcoded by the Dolphin team I thought a discussion is warranted.\r\n\r\n## Testing\r\n- Verified with DolphinTool header and DolphinTool verify\r\n- Verified with wit FILETYPE and wit DUMP (Wiimm's ISO Tools recognizes valid WBFS structure, partitions, encryption)\r\n- Tested ISO to WBFS and RVZ to WBFS conversions\r\n- Output file sizes match Wii Backup Manager when scrubbing is enabled (~0.1% difference), works when scrubbing is disabled.\r\n- Output WBFS files play correctly in Dolphin\r\n- Output WBFS files play correctly on a real Wii using USB Loader GX e25c4f3\r\n", 'reactions': {'url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/14731/reactions', 'total_count': 2, '+1': 2, '-1': 0, 'laugh': 0, 'hooray': 0, 'confused': 0, 'heart': 0, 'rocket': 0, 'eyes': 0}, 'timeline_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/14731/timeline', 'performed_via_github_app': None, 'state_reason': None}, 'comment': {'url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/comments/5013096819', 'html_url': 'https://github.com/dolphin-emu/dolphin/pull/14731#issuecomment-5013096819', 'issue_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/14731', 'id': 5013096819, 'node_id': 'IC_kwDOALCn2M8AAAABKs3Jcw', 'user': {'login': 'thethiny', 'id': 6018214, 'node_id': 'MDQ6VXNlcjYwMTgyMTQ=', 'avatar_url': 'https://avatars.githubusercontent.com/u/6018214?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/thethiny', 'html_url': 'https://github.com/thethiny', 'followers_url': 'https://api.github.com/users/thethiny/followers', 'following_url': 'https://api.github.com/users/thethiny/following{/other_user}', 'gists_url': 'https://api.github.com/users/thethiny/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/thethiny/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/thethiny/subscriptions', 'organizations_url': 'https://api.github.com/users/thethiny/orgs', 'repos_url': 'https://api.github.com/users/thethiny/repos', 'events_url': 'https://api.github.com/users/thethiny/events{/privacy}', 'received_events_url': 'https://api.github.com/users/thethiny/received_events', 'type': 'User', 'user_view_type': 'public', 'site_admin': False}, 'created_at': '2026-07-18T22:03:28Z', 'updated_at': '2026-07-18T22:03:28Z', 'body': "The build failures seem CMake related but I'm sure that I did it right so idk why it's failing", 'author_association': 'NONE', 'reactions': {'url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/comments/5013096819/reactions', 'total_count': 0, '+1': 0, '-1': 0, 'laugh': 0, 'hooray': 0, 'confused': 0, 'heart': 0, 'rocket': 0, 'eyes': 0}, 'performed_via_github_app': None, 'minimized': None}, 'repository': {'id': 11577304, 'node_id': 'MDEwOlJlcG9zaXRvcnkxMTU3NzMwNA==', 'name': 'dolphin', 'full_name': 'dolphin-emu/dolphin', 'private': False, 'owner': {'login': 'dolphin-emu', 'id': 5050316, 'node_id': 'MDEyOk9yZ2FuaXphdGlvbjUwNTAzMTY=', 'avatar_url': 'https://avatars.githubusercontent.com/u/5050316?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/dolphin-emu', 'html_url': 'https://github.com/dolphin-emu', 'followers_url': 'https://api.github.com/users/dolphin-emu/followers', 'following_url': 'https://api.github.com/users/dolphin-emu/following{/other_user}', 'gists_url': 'https://api.github.com/users/dolphin-emu/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/dolphin-emu/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/dolphin-emu/subscriptions', 'organizations_url': 'https://api.github.com/users/dolphin-emu/orgs', 'repos_url': 'https://api.github.com/users/dolphin-emu/repos', 'events_url': 'https://api.github.com/users/dolphin-emu/events{/privacy}', 'received_events_url': 'https://api.github.com/users/dolphin-emu/received_events', 'type': 'Organization', 'user_view_type': 'public', 'site_admin': False}, 'html_url': 'https://github.com/dolphin-emu/dolphin', 'description': 'Dolphin is a GameCube / Wii emulator, allowing you to play games for these two platforms on PC with improvements.', 'fork': False, 'url': 'https://api.github.com/repos/dolphin-emu/dolphin', 'forks_url': 'https://api.github.com/repos/dolphin-emu/dolphin/forks', 'keys_url': 'https://api.github.com/repos/dolphin-emu/dolphin/keys{/key_id}', 'collaborators_url': 'https://api.github.com/repos/dolphin-emu/dolphin/collaborators{/collaborator}', 'teams_url': 'https://api.github.com/repos/dolphin-emu/dolphin/teams', 'hooks_url': 'https://api.github.com/repos/dolphin-emu/dolphin/hooks', 'issue_events_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/events{/number}', 'events_url': 'https://api.github.com/repos/dolphin-emu/dolphin/events', 'assignees_url': 'https://api.github.com/repos/dolphin-emu/dolphin/assignees{/user}', 'branches_url': 'https://api.github.com/repos/dolphin-emu/dolphin/branches{/branch}', 'tags_url': 'https://api.github.com/repos/dolphin-emu/dolphin/tags', 'blobs_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/blobs{/sha}', 'git_tags_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/tags{/sha}', 'git_refs_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/refs{/sha}', 'trees_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/trees{/sha}', 'statuses_url': 'https://api.github.com/repos/dolphin-emu/dolphin/statuses/{sha}', 'languages_url': 'https://api.github.com/repos/dolphin-emu/dolphin/languages', 'stargazers_url': 'https://api.github.com/repos/dolphin-emu/dolphin/stargazers', 'contributors_url': 'https://api.github.com/repos/dolphin-emu/dolphin/contributors', 'subscribers_url': 'https://api.github.com/repos/dolphin-emu/dolphin/subscribers', 'subscription_url': 'https://api.github.com/repos/dolphin-emu/dolphin/subscription', 'commits_url': 'https://api.github.com/repos/dolphin-emu/dolphin/commits{/sha}', 'git_commits_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/commits{/sha}', 'comments_url': 'https://api.github.com/repos/dolphin-emu/dolphin/comments{/number}', 'issue_comment_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/comments{/number}', 'contents_url': 'https://api.github.com/repos/dolphin-emu/dolphin/contents/{+path}', 'compare_url': 'https://api.github.com/repos/dolphin-emu/dolphin/compare/{base}...{head}', 'merges_url': 'https://api.github.com/repos/dolphin-emu/dolphin/merges', 'archive_url': 'https://api.github.com/repos/dolphin-emu/dolphin/{archive_format}{/ref}', 'downloads_url': 'https://api.github.com/repos/dolphin-emu/dolphin/downloads', 'issues_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues{/number}', 'pulls_url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls{/number}', 'milestones_url': 'https://api.github.com/repos/dolphin-emu/dolphin/milestones{/number}', 'notifications_url': 'https://api.github.com/repos/dolphin-emu/dolphin/notifications{?since,all,participating}', 'labels_url': 'https://api.github.com/repos/dolphin-emu/dolphin/labels{/name}', 'releases_url': 'https://api.github.com/repos/dolphin-emu/dolphin/releases{/id}', 'deployments_url': 'https://api.github.com/repos/dolphin-emu/dolphin/deployments', 'created_at': '2013-07-22T09:07:57Z', 'updated_at': '2026-07-18T18:44:16Z', 'pushed_at': '2026-07-18T10:34:54Z', 'git_url': 'git://github.com/dolphin-emu/dolphin.git', 'ssh_url': 'git@github.com:dolphin-emu/dolphin.git', 'clone_url': 'https://github.com/dolphin-emu/dolphin.git', 'svn_url': 'https://github.com/dolphin-emu/dolphin', 'homepage': 'https://dolphin-emu.org', 'size': 558448, 'stargazers_count': 15272, 'watchers_count': 15272, 'language': 'C++', 'has_issues': False, 'has_projects': False, 'has_downloads': True, 'has_wiki': True, 'has_pages': False, 'has_discussions': False, 'forks_count': 3162, 'mirror_url': None, 'archived': False, 'disabled': False, 'open_issues_count': 446, 'license': {'key': 'other', 'name': 'Other', 'spdx_id': 'NOASSERTION', 'url': None, 'node_id': 'MDc6TGljZW5zZTA='}, 'allow_forking': True, 'is_template': False, 'web_commit_signoff_required': False, 'has_pull_requests': True, 'pull_request_creation_policy': 'all', 'topics': ['cpp', 'emulation', 'emulator', 'gamecube', 'wii'], 'visibility': 'public', 'forks': 3162, 'open_issues': 446, 'watchers': 15272, 'default_branch': 'master', 'custom_properties': {}}, 'organization': {'login': 'dolphin-emu', 'id': 5050316, 'node_id': 'MDEyOk9yZ2FuaXphdGlvbjUwNTAzMTY=', 'url': 'https://api.github.com/orgs/dolphin-emu', 'repos_url': 'https://api.github.com/orgs/dolphin-emu/repos', 'events_url': 'https://api.github.com/orgs/dolphin-emu/events', 'hooks_url': 'https://api.github.com/orgs/dolphin-emu/hooks', 'issues_url': 'https://api.github.com/orgs/dolphin-emu/issues', 'members_url': 'https://api.github.com/orgs/dolphin-emu/members{/member}', 'public_members_url': 'https://api.github.com/orgs/dolphin-emu/public_members{/member}', 'avatar_url': 'https://avatars.githubusercontent.com/u/5050316?v=4', 'description': ''}, 'sender': {'login': 'thethiny', 'id': 6018214, 'node_id': 'MDQ6VXNlcjYwMTgyMTQ=', 'avatar_url': 'https://avatars.githubusercontent.com/u/6018214?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/thethiny', 'html_url': 'https://github.com/thethiny', 'followers_url': 'https://api.github.com/users/thethiny/followers', 'following_url': 'https://api.github.com/users/thethiny/following{/other_user}', 'gists_url': 'https://api.github.com/users/thethiny/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/thethiny/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/thethiny/subscriptions', 'organizations_url': 'https://api.github.com/users/thethiny/orgs', 'repos_url': 'https://api.github.com/users/thethiny/repos', 'events_url': 'https://api.github.com/users/thethiny/events{/privacy}', 'received_events_url': 'https://api.github.com/users/thethiny/received_events', 'type': 'User', 'user_view_type': 'public', 'site_admin': False}, 'installation': {'id': 35437981, 'node_id': 'MDIzOkludGVncmF0aW9uSW5zdGFsbGF0aW9uMzU0Mzc5ODE='}}, 'type': 'gh_issue_comment'}
2026-07-18T20:58:04.066023	{'source': 'ghhookparser', 'repo': 'dolphin-emu/dolphin', 'author': 'thethiny', 'action': 'created', 'id': 14731, 'title': 'Convert To WBFS Support', 'url': 'https://github.com/dolphin-emu/dolphin/pull/14731#issuecomment-5012898695', 'safe_author': False, 'body': "one questio @phire \r\nin NKitHeader.cpp `ReadHeaderFromFile` I'm currently doing\r\n```\r\n  Header header;\r\n  file.Seek(offset, File::SeekOrigin::Begin);\r\n  if (!file.Read(reinterpret_cast<u8*>(&header), sizeof(header)))\r\n    return info;\r\n```\r\n\r\nIs this fine for here to be consistent with `ReadHeader`, or should I use `AsWritableU8Span`? `ReadHeader` (`BlobReader` variant) has to use `reinterpret_cast` because `BlobReader::Read` only takes `u8*` cuz it has no span overload. `DirectIOFile::Read` does have a span overload so `ReadHeaderFromFile` can use `AsWritableU8Span`. Should I prefer the cleaner API where available, or keep both consistent? Or should we extend `BlobReader::Read` to overload span?\r\n\r\n\r\n", 'raw': {'action': 'created', 'issue': {'url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/14731', 'repository_url': 'https://api.github.com/repos/dolphin-emu/dolphin', 'labels_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/14731/labels{/name}', 'comments_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/14731/comments', 'events_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/14731/events', 'html_url': 'https://github.com/dolphin-emu/dolphin/pull/14731', 'id': 4888393904, 'node_id': 'PR_kwDOALCn2M7x0I-2', 'number': 14731, 'title': 'Convert To WBFS Support', 'user': {'login': 'thethiny', 'id': 6018214, 'node_id': 'MDQ6VXNlcjYwMTgyMTQ=', 'avatar_url': 'https://avatars.githubusercontent.com/u/6018214?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/thethiny', 'html_url': 'https://github.com/thethiny', 'followers_url': 'https://api.github.com/users/thethiny/followers', 'following_url': 'https://api.github.com/users/thethiny/following{/other_user}', 'gists_url': 'https://api.github.com/users/thethiny/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/thethiny/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/thethiny/subscriptions', 'organizations_url': 'https://api.github.com/users/thethiny/orgs', 'repos_url': 'https://api.github.com/users/thethiny/repos', 'events_url': 'https://api.github.com/users/thethiny/events{/privacy}', 'received_events_url': 'https://api.github.com/users/thethiny/received_events', 'type': 'User', 'user_view_type': 'public', 'site_admin': False}, 'labels': [], 'state': 'open', 'locked': False, 'assignees': [], 'milestone': None, 'comments': 40, 'created_at': '2026-07-15T01:16:25Z', 'updated_at': '2026-07-18T20:58:01Z', 'closed_at': None, 'assignee': None, 'author_association': 'NONE', 'issue_field_values': [], 'type': None, 'active_lock_reason': None, 'draft': False, 'pull_request': {'url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/14731', 'html_url': 'https://github.com/dolphin-emu/dolphin/pull/14731', 'diff_url': 'https://github.com/dolphin-emu/dolphin/pull/14731.diff', 'patch_url': 'https://github.com/dolphin-emu/dolphin/pull/14731.patch', 'merged_at': None}, 'body': "This PR introduces Conversion **to** WBFS support. WBFS is the format that is used by USB Loaders on a real Wii device.\r\n\r\n## Design decisions & hardcoded values\r\nThe writer uses fixed sector sizes that match what [libwbfs (the reference implementation by kwiirk)](https://github.com/kwiirk/wbfs/blob/master/libwbfs/libwbfs.c#L128-L134) computes for a standard single-layer Wii disc. These 2 hardcodes are stable and work correctly across all my testings.\r\n- HD sector shift: 9 (512 bytes)\r\n- WBFS sector shift: 21 (2 MiB)\r\nThese are not configurable via the UI. All existing WBFS tools use these values, and since the aim is to support USB Loaders then this has been tested and it is working on a real Wii.\r\n\r\nConverting from WBFS is not enabled. The existing `WbfsFileReader` reports `DataSizeType::UpperBound`, and `ShouldAllowConversion()` requires `Accurate`. I am able to support this but since it was hardcoded by the Dolphin team I thought a discussion is warranted.\r\n\r\n## Testing\r\n- Verified with DolphinTool header and DolphinTool verify\r\n- Verified with wit FILETYPE and wit DUMP (Wiimm's ISO Tools recognizes valid WBFS structure, partitions, encryption)\r\n- Tested ISO to WBFS and RVZ to WBFS conversions\r\n- Output file sizes match Wii Backup Manager when scrubbing is enabled (~0.1% difference), works when scrubbing is disabled.\r\n- Output WBFS files play correctly in Dolphin\r\n- Output WBFS files play correctly on a real Wii using USB Loader GX e25c4f3\r\n", 'reactions': {'url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/14731/reactions', 'total_count': 2, '+1': 2, '-1': 0, 'laugh': 0, 'hooray': 0, 'confused': 0, 'heart': 0, 'rocket': 0, 'eyes': 0}, 'timeline_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/14731/timeline', 'performed_via_github_app': None, 'state_reason': None}, 'comment': {'url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/comments/5012898695', 'html_url': 'https://github.com/dolphin-emu/dolphin/pull/14731#issuecomment-5012898695', 'issue_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/14731', 'id': 5012898695, 'node_id': 'IC_kwDOALCn2M8AAAABKsrDhw', 'user': {'login': 'thethiny', 'id': 6018214, 'node_id': 'MDQ6VXNlcjYwMTgyMTQ=', 'avatar_url': 'https://avatars.githubusercontent.com/u/6018214?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/thethiny', 'html_url': 'https://github.com/thethiny', 'followers_url': 'https://api.github.com/users/thethiny/followers', 'following_url': 'https://api.github.com/users/thethiny/following{/other_user}', 'gists_url': 'https://api.github.com/users/thethiny/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/thethiny/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/thethiny/subscriptions', 'organizations_url': 'https://api.github.com/users/thethiny/orgs', 'repos_url': 'https://api.github.com/users/thethiny/repos', 'events_url': 'https://api.github.com/users/thethiny/events{/privacy}', 'received_events_url': 'https://api.github.com/users/thethiny/received_events', 'type': 'User', 'user_view_type': 'public', 'site_admin': False}, 'created_at': '2026-07-18T20:58:01Z', 'updated_at': '2026-07-18T20:58:01Z', 'body': "one questio @phire \r\nin NKitHeader.cpp `ReadHeaderFromFile` I'm currently doing\r\n```\r\n  Header header;\r\n  file.Seek(offset, File::SeekOrigin::Begin);\r\n  if (!file.Read(reinterpret_cast<u8*>(&header), sizeof(header)))\r\n    return info;\r\n```\r\n\r\nIs this fine for here to be consistent with `ReadHeader`, or should I use `AsWritableU8Span`? `ReadHeader` (`BlobReader` variant) has to use `reinterpret_cast` because `BlobReader::Read` only takes `u8*` cuz it has no span overload. `DirectIOFile::Read` does have a span overload so `ReadHeaderFromFile` can use `AsWritableU8Span`. Should I prefer the cleaner API where available, or keep both consistent? Or should we extend `BlobReader::Read` to overload span?\r\n\r\n\r\n", 'author_association': 'NONE', 'reactions': {'url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/comments/5012898695/reactions', 'total_count': 0, '+1': 0, '-1': 0, 'laugh': 0, 'hooray': 0, 'confused': 0, 'heart': 0, 'rocket': 0, 'eyes': 0}, 'performed_via_github_app': None, 'minimized': None}, 'repository': {'id': 11577304, 'node_id': 'MDEwOlJlcG9zaXRvcnkxMTU3NzMwNA==', 'name': 'dolphin', 'full_name': 'dolphin-emu/dolphin', 'private': False, 'owner': {'login': 'dolphin-emu', 'id': 5050316, 'node_id': 'MDEyOk9yZ2FuaXphdGlvbjUwNTAzMTY=', 'avatar_url': 'https://avatars.githubusercontent.com/u/5050316?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/dolphin-emu', 'html_url': 'https://github.com/dolphin-emu', 'followers_url': 'https://api.github.com/users/dolphin-emu/followers', 'following_url': 'https://api.github.com/users/dolphin-emu/following{/other_user}', 'gists_url': 'https://api.github.com/users/dolphin-emu/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/dolphin-emu/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/dolphin-emu/subscriptions', 'organizations_url': 'https://api.github.com/users/dolphin-emu/orgs', 'repos_url': 'https://api.github.com/users/dolphin-emu/repos', 'events_url': 'https://api.github.com/users/dolphin-emu/events{/privacy}', 'received_events_url': 'https://api.github.com/users/dolphin-emu/received_events', 'type': 'Organization', 'user_view_type': 'public', 'site_admin': False}, 'html_url': 'https://github.com/dolphin-emu/dolphin', 'description': 'Dolphin is a GameCube / Wii emulator, allowing you to play games for these two platforms on PC with improvements.', 'fork': False, 'url': 'https://api.github.com/repos/dolphin-emu/dolphin', 'forks_url': 'https://api.github.com/repos/dolphin-emu/dolphin/forks', 'keys_url': 'https://api.github.com/repos/dolphin-emu/dolphin/keys{/key_id}', 'collaborators_url': 'https://api.github.com/repos/dolphin-emu/dolphin/collaborators{/collaborator}', 'teams_url': 'https://api.github.com/repos/dolphin-emu/dolphin/teams', 'hooks_url': 'https://api.github.com/repos/dolphin-emu/dolphin/hooks', 'issue_events_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/events{/number}', 'events_url': 'https://api.github.com/repos/dolphin-emu/dolphin/events', 'assignees_url': 'https://api.github.com/repos/dolphin-emu/dolphin/assignees{/user}', 'branches_url': 'https://api.github.com/repos/dolphin-emu/dolphin/branches{/branch}', 'tags_url': 'https://api.github.com/repos/dolphin-emu/dolphin/tags', 'blobs_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/blobs{/sha}', 'git_tags_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/tags{/sha}', 'git_refs_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/refs{/sha}', 'trees_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/trees{/sha}', 'statuses_url': 'https://api.github.com/repos/dolphin-emu/dolphin/statuses/{sha}', 'languages_url': 'https://api.github.com/repos/dolphin-emu/dolphin/languages', 'stargazers_url': 'https://api.github.com/repos/dolphin-emu/dolphin/stargazers', 'contributors_url': 'https://api.github.com/repos/dolphin-emu/dolphin/contributors', 'subscribers_url': 'https://api.github.com/repos/dolphin-emu/dolphin/subscribers', 'subscription_url': 'https://api.github.com/repos/dolphin-emu/dolphin/subscription', 'commits_url': 'https://api.github.com/repos/dolphin-emu/dolphin/commits{/sha}', 'git_commits_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/commits{/sha}', 'comments_url': 'https://api.github.com/repos/dolphin-emu/dolphin/comments{/number}', 'issue_comment_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/comments{/number}', 'contents_url': 'https://api.github.com/repos/dolphin-emu/dolphin/contents/{+path}', 'compare_url': 'https://api.github.com/repos/dolphin-emu/dolphin/compare/{base}...{head}', 'merges_url': 'https://api.github.com/repos/dolphin-emu/dolphin/merges', 'archive_url': 'https://api.github.com/repos/dolphin-emu/dolphin/{archive_format}{/ref}', 'downloads_url': 'https://api.github.com/repos/dolphin-emu/dolphin/downloads', 'issues_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues{/number}', 'pulls_url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls{/number}', 'milestones_url': 'https://api.github.com/repos/dolphin-emu/dolphin/milestones{/number}', 'notifications_url': 'https://api.github.com/repos/dolphin-emu/dolphin/notifications{?since,all,participating}', 'labels_url': 'https://api.github.com/repos/dolphin-emu/dolphin/labels{/name}', 'releases_url': 'https://api.github.com/repos/dolphin-emu/dolphin/releases{/id}', 'deployments_url': 'https://api.github.com/repos/dolphin-emu/dolphin/deployments', 'created_at': '2013-07-22T09:07:57Z', 'updated_at': '2026-07-18T18:44:16Z', 'pushed_at': '2026-07-18T10:34:54Z', 'git_url': 'git://github.com/dolphin-emu/dolphin.git', 'ssh_url': 'git@github.com:dolphin-emu/dolphin.git', 'clone_url': 'https://github.com/dolphin-emu/dolphin.git', 'svn_url': 'https://github.com/dolphin-emu/dolphin', 'homepage': 'https://dolphin-emu.org', 'size': 558448, 'stargazers_count': 15272, 'watchers_count': 15272, 'language': 'C++', 'has_issues': False, 'has_projects': False, 'has_downloads': True, 'has_wiki': True, 'has_pages': False, 'has_discussions': False, 'forks_count': 3161, 'mirror_url': None, 'archived': False, 'disabled': False, 'open_issues_count': 446, 'license': {'key': 'other', 'name': 'Other', 'spdx_id': 'NOASSERTION', 'url': None, 'node_id': 'MDc6TGljZW5zZTA='}, 'allow_forking': True, 'is_template': False, 'web_commit_signoff_required': False, 'has_pull_requests': True, 'pull_request_creation_policy': 'all', 'topics': ['cpp', 'emulation', 'emulator', 'gamecube', 'wii'], 'visibility': 'public', 'forks': 3161, 'open_issues': 446, 'watchers': 15272, 'default_branch': 'master', 'custom_properties': {}}, 'organization': {'login': 'dolphin-emu', 'id': 5050316, 'node_id': 'MDEyOk9yZ2FuaXphdGlvbjUwNTAzMTY=', 'url': 'https://api.github.com/orgs/dolphin-emu', 'repos_url': 'https://api.github.com/orgs/dolphin-emu/repos', 'events_url': 'https://api.github.com/orgs/dolphin-emu/events', 'hooks_url': 'https://api.github.com/orgs/dolphin-emu/hooks', 'issues_url': 'https://api.github.com/orgs/dolphin-emu/issues', 'members_url': 'https://api.github.com/orgs/dolphin-emu/members{/member}', 'public_members_url': 'https://api.github.com/orgs/dolphin-emu/public_members{/member}', 'avatar_url': 'https://avatars.githubusercontent.com/u/5050316?v=4', 'description': ''}, 'sender': {'login': 'thethiny', 'id': 6018214, 'node_id': 'MDQ6VXNlcjYwMTgyMTQ=', 'avatar_url': 'https://avatars.githubusercontent.com/u/6018214?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/thethiny', 'html_url': 'https://github.com/thethiny', 'followers_url': 'https://api.github.com/users/thethiny/followers', 'following_url': 'https://api.github.com/users/thethiny/following{/other_user}', 'gists_url': 'https://api.github.com/users/thethiny/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/thethiny/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/thethiny/subscriptions', 'organizations_url': 'https://api.github.com/users/thethiny/orgs', 'repos_url': 'https://api.github.com/users/thethiny/repos', 'events_url': 'https://api.github.com/users/thethiny/events{/privacy}', 'received_events_url': 'https://api.github.com/users/thethiny/received_events', 'type': 'User', 'user_view_type': 'public', 'site_admin': False}, 'installation': {'id': 35437981, 'node_id': 'MDIzOkludGVncmF0aW9uSW5zdGFsbGF0aW9uMzU0Mzc5ODE='}}, 'type': 'gh_issue_comment'}
2026-07-18T20:36:10.807363	{'source': 'ghhookparser', 'repo': 'dolphin-emu/dolphin', 'author': 'LordNyriox', 'action': 'created', 'id': 13025, 'title': 'Core & UnitTests: Join declarations and assignments', 'url': 'https://github.com/dolphin-emu/dolphin/pull/13025#issuecomment-5012831867', 'safe_author': False, 'body': '@tygyh:\n\n```patch\n!!! Source/Core/DolphinQt/SkylanderPortal/SkylanderPortalWindow.cpp not compliant to coding style, here is the fix:\n--- Source/Core/DolphinQt/SkylanderPortal/SkylanderPortalWindow.cpp\t2026-07-18 19:43:41.190329943 +0000\n+++ -\t2026-07-18 19:43:44.556332141 +0000\n@@ -515,10 +515,10 @@\n \n   if (file_path.isEmpty())\n   {\n-    QMessageBox::StandardButton create_file_response = QMessageBox::question(\n-        this, tr("Create Skylander File"),\n-        tr("Skylander not found in this collection. Create new file?"),\n-        QMessageBox::Yes | QMessageBox::No);\n+    QMessageBox::StandardButton create_file_response =\n+        QMessageBox::question(this, tr("Create Skylander File"),\n+                              tr("Skylander not found in this collection. Create new file?"),\n+                              QMessageBox::Yes | QMessageBox::No);\n \n     if (create_file_response == QMessageBox::Yes)\n     {\n!!! Source/Core/VideoBackends/Vulkan/VKSwapChain.cpp not compliant to coding style, here is the fix:\n--- Source/Core/VideoBackends/Vulkan/VKSwapChain.cpp\t2026-07-18 19:43:41.191329924 +0000\n+++ -\t2026-07-18 19:43:44.668459993 +0000\n@@ -229,8 +229,8 @@\n bool SwapChain::SelectPresentMode()\n {\n   u32 mode_count;\n-  VkResult res = vkGetPhysicalDeviceSurfacePresentModesKHR(g_vulkan_context->GetPhysicalDevice(), m_surface,\n-                                                           &mode_count, nullptr);\n+  VkResult res = vkGetPhysicalDeviceSurfacePresentModesKHR(g_vulkan_context->GetPhysicalDevice(),\n+                                                           m_surface, &mode_count, nullptr);\n   if (res != VK_SUCCESS || mode_count == 0)\n   {\n     LOG_VULKAN_ERROR(res, "vkGetPhysicalDeviceSurfaceFormatsKHR failed: ");\n!!! Source/Core/VideoCommon/TextureDecoder_x64.cpp not compliant to coding style, here is the fix:\n--- Source/Core/VideoCommon/TextureDecoder_x64.cpp\t2026-07-18 19:43:41.192329904 +0000\n+++ -\t2026-07-18 19:43:44.870156768 +0000\n@@ -408,8 +408,8 @@\n         // Load 64 bits from `src` into an __m128i with upper 64 bits zeroed: (0000 0000 hgfe dcba)\n         __m128i r = _mm_loadl_epi64((const __m128i*)(src + 8 * xStep));\n         // Shuffle select bytes to expand from (0000 0000 hgfe dcba) to:\n-        __m128i rgba0 = _mm_shuffle_epi8(r, mask3210); // (dddd cccc bbbb aaaa)\n-        __m128i rgba1 = _mm_shuffle_epi8(r, mask7654); // (hhhh gggg ffff eeee)\n+        __m128i rgba0 = _mm_shuffle_epi8(r, mask3210);  // (dddd cccc bbbb aaaa)\n+        __m128i rgba1 = _mm_shuffle_epi8(r, mask7654);  // (hhhh gggg ffff eeee)\n \n         __m128i* quaddst = (__m128i*)(dst + (y + iy) * width + x);\n         _mm_storeu_si128(quaddst, rgba0);\n!!! Source/Core/VideoCommon/VertexLoader_Color.cpp not compliant to coding style, here is the fix:\n--- Source/Core/VideoCommon/VertexLoader_Color.cpp\t2026-07-18 19:43:41.193329885 +0000\n+++ -\t2026-07-18 19:43:44.971007610 +0000\n@@ -34,7 +34,7 @@\n void SetCol4444(VertexLoader* loader, u16 val_)\n {\n   u32 val = val_;\n-  u32 col = val & 0x00F0;           // col  = 000000R0;\n+  u32 col = val & 0x00F0;       // col  = 000000R0;\n   col |= (val & 0x000F) << 12;  // col |= 0000G000;\n   col |= (val & 0xF000) << 8;   // col |= 00B00000;\n   col |= (val & 0x0F00) << 20;  // col |= A0000000;\n```', 'raw': {'action': 'created', 'issue': {'url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/13025', 'repository_url': 'https://api.github.com/repos/dolphin-emu/dolphin', 'labels_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/13025/labels{/name}', 'comments_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/13025/comments', 'events_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/13025/events', 'html_url': 'https://github.com/dolphin-emu/dolphin/pull/13025', 'id': 2472864028, 'node_id': 'PR_kwDOALCn2M54tZSd', 'number': 13025, 'title': 'Core & UnitTests: Join declarations and assignments', 'user': {'login': 'tygyh', 'id': 32486062, 'node_id': 'MDQ6VXNlcjMyNDg2MDYy', 'avatar_url': 'https://avatars.githubusercontent.com/u/32486062?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/tygyh', 'html_url': 'https://github.com/tygyh', 'followers_url': 'https://api.github.com/users/tygyh/followers', 'following_url': 'https://api.github.com/users/tygyh/following{/other_user}', 'gists_url': 'https://api.github.com/users/tygyh/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/tygyh/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/tygyh/subscriptions', 'organizations_url': 'https://api.github.com/users/tygyh/orgs', 'repos_url': 'https://api.github.com/users/tygyh/repos', 'events_url': 'https://api.github.com/users/tygyh/events{/privacy}', 'received_events_url': 'https://api.github.com/users/tygyh/received_events', 'type': 'User', 'user_view_type': 'public', 'site_admin': False}, 'labels': [], 'state': 'open', 'locked': False, 'assignees': [], 'milestone': None, 'comments': 2, 'created_at': '2024-08-19T09:13:28Z', 'updated_at': '2026-07-18T20:36:09Z', 'closed_at': None, 'assignee': None, 'author_association': 'CONTRIBUTOR', 'issue_field_values': [], 'type': None, 'active_lock_reason': None, 'draft': False, 'pull_request': {'url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/13025', 'html_url': 'https://github.com/dolphin-emu/dolphin/pull/13025', 'diff_url': 'https://github.com/dolphin-emu/dolphin/pull/13025.diff', 'patch_url': 'https://github.com/dolphin-emu/dolphin/pull/13025.patch', 'merged_at': None}, 'body': None, 'reactions': {'url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/13025/reactions', 'total_count': 0, '+1': 0, '-1': 0, 'laugh': 0, 'hooray': 0, 'confused': 0, 'heart': 0, 'rocket': 0, 'eyes': 0}, 'timeline_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/13025/timeline', 'performed_via_github_app': None, 'state_reason': None}, 'comment': {'url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/comments/5012831867', 'html_url': 'https://github.com/dolphin-emu/dolphin/pull/13025#issuecomment-5012831867', 'issue_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/13025', 'id': 5012831867, 'node_id': 'IC_kwDOALCn2M8AAAABKsm-ew', 'user': {'login': 'LordNyriox', 'id': 3100578, 'node_id': 'MDQ6VXNlcjMxMDA1Nzg=', 'avatar_url': 'https://avatars.githubusercontent.com/u/3100578?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/LordNyriox', 'html_url': 'https://github.com/LordNyriox', 'followers_url': 'https://api.github.com/users/LordNyriox/followers', 'following_url': 'https://api.github.com/users/LordNyriox/following{/other_user}', 'gists_url': 'https://api.github.com/users/LordNyriox/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/LordNyriox/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/LordNyriox/subscriptions', 'organizations_url': 'https://api.github.com/users/LordNyriox/orgs', 'repos_url': 'https://api.github.com/users/LordNyriox/repos', 'events_url': 'https://api.github.com/users/LordNyriox/events{/privacy}', 'received_events_url': 'https://api.github.com/users/LordNyriox/received_events', 'type': 'User', 'user_view_type': 'public', 'site_admin': False}, 'created_at': '2026-07-18T20:36:09Z', 'updated_at': '2026-07-18T20:36:09Z', 'body': '@tygyh:\n\n```patch\n!!! Source/Core/DolphinQt/SkylanderPortal/SkylanderPortalWindow.cpp not compliant to coding style, here is the fix:\n--- Source/Core/DolphinQt/SkylanderPortal/SkylanderPortalWindow.cpp\t2026-07-18 19:43:41.190329943 +0000\n+++ -\t2026-07-18 19:43:44.556332141 +0000\n@@ -515,10 +515,10 @@\n \n   if (file_path.isEmpty())\n   {\n-    QMessageBox::StandardButton create_file_response = QMessageBox::question(\n-        this, tr("Create Skylander File"),\n-        tr("Skylander not found in this collection. Create new file?"),\n-        QMessageBox::Yes | QMessageBox::No);\n+    QMessageBox::StandardButton create_file_response =\n+        QMessageBox::question(this, tr("Create Skylander File"),\n+                              tr("Skylander not found in this collection. Create new file?"),\n+                              QMessageBox::Yes | QMessageBox::No);\n \n     if (create_file_response == QMessageBox::Yes)\n     {\n!!! Source/Core/VideoBackends/Vulkan/VKSwapChain.cpp not compliant to coding style, here is the fix:\n--- Source/Core/VideoBackends/Vulkan/VKSwapChain.cpp\t2026-07-18 19:43:41.191329924 +0000\n+++ -\t2026-07-18 19:43:44.668459993 +0000\n@@ -229,8 +229,8 @@\n bool SwapChain::SelectPresentMode()\n {\n   u32 mode_count;\n-  VkResult res = vkGetPhysicalDeviceSurfacePresentModesKHR(g_vulkan_context->GetPhysicalDevice(), m_surface,\n-                                                           &mode_count, nullptr);\n+  VkResult res = vkGetPhysicalDeviceSurfacePresentModesKHR(g_vulkan_context->GetPhysicalDevice(),\n+                                                           m_surface, &mode_count, nullptr);\n   if (res != VK_SUCCESS || mode_count == 0)\n   {\n     LOG_VULKAN_ERROR(res, "vkGetPhysicalDeviceSurfaceFormatsKHR failed: ");\n!!! Source/Core/VideoCommon/TextureDecoder_x64.cpp not compliant to coding style, here is the fix:\n--- Source/Core/VideoCommon/TextureDecoder_x64.cpp\t2026-07-18 19:43:41.192329904 +0000\n+++ -\t2026-07-18 19:43:44.870156768 +0000\n@@ -408,8 +408,8 @@\n         // Load 64 bits from `src` into an __m128i with upper 64 bits zeroed: (0000 0000 hgfe dcba)\n         __m128i r = _mm_loadl_epi64((const __m128i*)(src + 8 * xStep));\n         // Shuffle select bytes to expand from (0000 0000 hgfe dcba) to:\n-        __m128i rgba0 = _mm_shuffle_epi8(r, mask3210); // (dddd cccc bbbb aaaa)\n-        __m128i rgba1 = _mm_shuffle_epi8(r, mask7654); // (hhhh gggg ffff eeee)\n+        __m128i rgba0 = _mm_shuffle_epi8(r, mask3210);  // (dddd cccc bbbb aaaa)\n+        __m128i rgba1 = _mm_shuffle_epi8(r, mask7654);  // (hhhh gggg ffff eeee)\n \n         __m128i* quaddst = (__m128i*)(dst + (y + iy) * width + x);\n         _mm_storeu_si128(quaddst, rgba0);\n!!! Source/Core/VideoCommon/VertexLoader_Color.cpp not compliant to coding style, here is the fix:\n--- Source/Core/VideoCommon/VertexLoader_Color.cpp\t2026-07-18 19:43:41.193329885 +0000\n+++ -\t2026-07-18 19:43:44.971007610 +0000\n@@ -34,7 +34,7 @@\n void SetCol4444(VertexLoader* loader, u16 val_)\n {\n   u32 val = val_;\n-  u32 col = val & 0x00F0;           // col  = 000000R0;\n+  u32 col = val & 0x00F0;       // col  = 000000R0;\n   col |= (val & 0x000F) << 12;  // col |= 0000G000;\n   col |= (val & 0xF000) << 8;   // col |= 00B00000;\n   col |= (val & 0x0F00) << 20;  // col |= A0000000;\n```', 'author_association': 'NONE', 'reactions': {'url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/comments/5012831867/reactions', 'total_count': 0, '+1': 0, '-1': 0, 'laugh': 0, 'hooray': 0, 'confused': 0, 'heart': 0, 'rocket': 0, 'eyes': 0}, 'performed_via_github_app': None, 'minimized': None}, 'repository': {'id': 11577304, 'node_id': 'MDEwOlJlcG9zaXRvcnkxMTU3NzMwNA==', 'name': 'dolphin', 'full_name': 'dolphin-emu/dolphin', 'private': False, 'owner': {'login': 'dolphin-emu', 'id': 5050316, 'node_id': 'MDEyOk9yZ2FuaXphdGlvbjUwNTAzMTY=', 'avatar_url': 'https://avatars.githubusercontent.com/u/5050316?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/dolphin-emu', 'html_url': 'https://github.com/dolphin-emu', 'followers_url': 'https://api.github.com/users/dolphin-emu/followers', 'following_url': 'https://api.github.com/users/dolphin-emu/following{/other_user}', 'gists_url': 'https://api.github.com/users/dolphin-emu/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/dolphin-emu/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/dolphin-emu/subscriptions', 'organizations_url': 'https://api.github.com/users/dolphin-emu/orgs', 'repos_url': 'https://api.github.com/users/dolphin-emu/repos', 'events_url': 'https://api.github.com/users/dolphin-emu/events{/privacy}', 'received_events_url': 'https://api.github.com/users/dolphin-emu/received_events', 'type': 'Organization', 'user_view_type': 'public', 'site_admin': False}, 'html_url': 'https://github.com/dolphin-emu/dolphin', 'description': 'Dolphin is a GameCube / Wii emulator, allowing you to play games for these two platforms on PC with improvements.', 'fork': False, 'url': 'https://api.github.com/repos/dolphin-emu/dolphin', 'forks_url': 'https://api.github.com/repos/dolphin-emu/dolphin/forks', 'keys_url': 'https://api.github.com/repos/dolphin-emu/dolphin/keys{/key_id}', 'collaborators_url': 'https://api.github.com/repos/dolphin-emu/dolphin/collaborators{/collaborator}', 'teams_url': 'https://api.github.com/repos/dolphin-emu/dolphin/teams', 'hooks_url': 'https://api.github.com/repos/dolphin-emu/dolphin/hooks', 'issue_events_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/events{/number}', 'events_url': 'https://api.github.com/repos/dolphin-emu/dolphin/events', 'assignees_url': 'https://api.github.com/repos/dolphin-emu/dolphin/assignees{/user}', 'branches_url': 'https://api.github.com/repos/dolphin-emu/dolphin/branches{/branch}', 'tags_url': 'https://api.github.com/repos/dolphin-emu/dolphin/tags', 'blobs_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/blobs{/sha}', 'git_tags_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/tags{/sha}', 'git_refs_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/refs{/sha}', 'trees_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/trees{/sha}', 'statuses_url': 'https://api.github.com/repos/dolphin-emu/dolphin/statuses/{sha}', 'languages_url': 'https://api.github.com/repos/dolphin-emu/dolphin/languages', 'stargazers_url': 'https://api.github.com/repos/dolphin-emu/dolphin/stargazers', 'contributors_url': 'https://api.github.com/repos/dolphin-emu/dolphin/contributors', 'subscribers_url': 'https://api.github.com/repos/dolphin-emu/dolphin/subscribers', 'subscription_url': 'https://api.github.com/repos/dolphin-emu/dolphin/subscription', 'commits_url': 'https://api.github.com/repos/dolphin-emu/dolphin/commits{/sha}', 'git_commits_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/commits{/sha}', 'comments_url': 'https://api.github.com/repos/dolphin-emu/dolphin/comments{/number}', 'issue_comment_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/comments{/number}', 'contents_url': 'https://api.github.com/repos/dolphin-emu/dolphin/contents/{+path}', 'compare_url': 'https://api.github.com/repos/dolphin-emu/dolphin/compare/{base}...{head}', 'merges_url': 'https://api.github.com/repos/dolphin-emu/dolphin/merges', 'archive_url': 'https://api.github.com/repos/dolphin-emu/dolphin/{archive_format}{/ref}', 'downloads_url': 'https://api.github.com/repos/dolphin-emu/dolphin/downloads', 'issues_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues{/number}', 'pulls_url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls{/number}', 'milestones_url': 'https://api.github.com/repos/dolphin-emu/dolphin/milestones{/number}', 'notifications_url': 'https://api.github.com/repos/dolphin-emu/dolphin/notifications{?since,all,participating}', 'labels_url': 'https://api.github.com/repos/dolphin-emu/dolphin/labels{/name}', 'releases_url': 'https://api.github.com/repos/dolphin-emu/dolphin/releases{/id}', 'deployments_url': 'https://api.github.com/repos/dolphin-emu/dolphin/deployments', 'created_at': '2013-07-22T09:07:57Z', 'updated_at': '2026-07-18T18:44:16Z', 'pushed_at': '2026-07-18T10:34:54Z', 'git_url': 'git://github.com/dolphin-emu/dolphin.git', 'ssh_url': 'git@github.com:dolphin-emu/dolphin.git', 'clone_url': 'https://github.com/dolphin-emu/dolphin.git', 'svn_url': 'https://github.com/dolphin-emu/dolphin', 'homepage': 'https://dolphin-emu.org', 'size': 558448, 'stargazers_count': 15272, 'watchers_count': 15272, 'language': 'C++', 'has_issues': False, 'has_projects': False, 'has_downloads': True, 'has_wiki': True, 'has_pages': False, 'has_discussions': False, 'forks_count': 3161, 'mirror_url': None, 'archived': False, 'disabled': False, 'open_issues_count': 446, 'license': {'key': 'other', 'name': 'Other', 'spdx_id': 'NOASSERTION', 'url': None, 'node_id': 'MDc6TGljZW5zZTA='}, 'allow_forking': True, 'is_template': False, 'web_commit_signoff_required': False, 'has_pull_requests': True, 'pull_request_creation_policy': 'all', 'topics': ['cpp', 'emulation', 'emulator', 'gamecube', 'wii'], 'visibility': 'public', 'forks': 3161, 'open_issues': 446, 'watchers': 15272, 'default_branch': 'master', 'custom_properties': {}}, 'organization': {'login': 'dolphin-emu', 'id': 5050316, 'node_id': 'MDEyOk9yZ2FuaXphdGlvbjUwNTAzMTY=', 'url': 'https://api.github.com/orgs/dolphin-emu', 'repos_url': 'https://api.github.com/orgs/dolphin-emu/repos', 'events_url': 'https://api.github.com/orgs/dolphin-emu/events', 'hooks_url': 'https://api.github.com/orgs/dolphin-emu/hooks', 'issues_url': 'https://api.github.com/orgs/dolphin-emu/issues', 'members_url': 'https://api.github.com/orgs/dolphin-emu/members{/member}', 'public_members_url': 'https://api.github.com/orgs/dolphin-emu/public_members{/member}', 'avatar_url': 'https://avatars.githubusercontent.com/u/5050316?v=4', 'description': ''}, 'sender': {'login': 'LordNyriox', 'id': 3100578, 'node_id': 'MDQ6VXNlcjMxMDA1Nzg=', 'avatar_url': 'https://avatars.githubusercontent.com/u/3100578?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/LordNyriox', 'html_url': 'https://github.com/LordNyriox', 'followers_url': 'https://api.github.com/users/LordNyriox/followers', 'following_url': 'https://api.github.com/users/LordNyriox/following{/other_user}', 'gists_url': 'https://api.github.com/users/LordNyriox/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/LordNyriox/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/LordNyriox/subscriptions', 'organizations_url': 'https://api.github.com/users/LordNyriox/orgs', 'repos_url': 'https://api.github.com/users/LordNyriox/repos', 'events_url': 'https://api.github.com/users/LordNyriox/events{/privacy}', 'received_events_url': 'https://api.github.com/users/LordNyriox/received_events', 'type': 'User', 'user_view_type': 'public', 'site_admin': False}, 'installation': {'id': 35437981, 'node_id': 'MDIzOkludGVncmF0aW9uSW5zdGFsbGF0aW9uMzU0Mzc5ODE='}}, 'type': 'gh_issue_comment'}
2026-07-18T20:15:24.825142	{'source': 'ghhookparser', 'repo': 'dolphin-emu/dolphin', 'author': 'thethiny', 'action': 'created', 'id': 14731, 'title': 'Convert To WBFS Support', 'url': 'https://github.com/dolphin-emu/dolphin/pull/14731#issuecomment-5012766235', 'safe_author': False, 'body': "Pushed commits addressing the code review feedback. Here's what changed and what's still open.\r\n\r\n## Commits\r\n\r\n**Bundle B: Skip disc-level junk checks for partition data**\r\nDisc-level zero and LFG junk checks now only run on non-partition regions. Partition data is encrypted and can never match these patterns.\r\n\r\n**Bundle A: Code quality fixes**\r\nRemoved redundant buffer zeroing, cast `sz` to `size_t` once, skip junk check when sector is already zero, use `std::ranges::find_if` for partition lookup.\r\n\r\n**Bundle D: Single-pass writer**\r\nMerged scan and write into a single loop - used sectors are written during the scan, headers are written by seeking back at the end. Halves disc I/O.\r\n\r\n**Bundle F2: Use Volume::Read for partition junk checks (writer)**\r\nWriter now uses `Volume::Read` for decrypted partition data instead of manual AES. Format-agnostic - avoids encrypt-then-decrypt round-trips for WIA/RVZ input.\r\n\r\n**Bundle F1: Simplify ReadWiiDecrypted (reader)**\r\n`SupportsReadWiiDecrypted` now returns true only for non-stored blocks (wlba == 0). For stored blocks, VolumeWii handles decryption through the normal `Read()` path.\r\n\r\n**Bundle C: NKit header refactor**\r\nMoved NKit code into standalone `NKitHeader.h/cpp` under `DiscIO::NKit`. Packed structs with `BigEndianValue`, `NKit::Flags` enum from Nanook's full spec, Key field corrected to `u8 key_length + u8 key_type`. Future-facing `ComputeDigests` and `Verify` API included but not yet called.\r\n\r\n**Lossy WBFS/CISO conversion warning**\r\nSoft warning when converting FROM `DataSizeType::UpperBound` files. Asserts relaxed to `== Accurate || == UpperBound` in all 4 converters. `ShouldAllowConversion` updated.\r\n\r\n**Cleanup**\r\nRemoved dead code (`m_wbfs_sector_count`, `m_nkit_disc_size`), renamed to NKit terminology (`gap_type`, `IsGapJunk`), dynamic `WriteHeader` size, deduplicated read parsers, added `mbedtls_md5_free` on all return paths.\r\n\r\n## Known Limitation\r\n\r\n`ReadWiiDecrypted` still contains manual AES decryption for stored blocks because `VolumeWii::EncryptGroup` calls it directly without checking `SupportsReadWiiDecrypted`. Fixing this would require modifying shared `VolumeWii` code - out of scope for this PR.\r\n\r\n## Benchmarks\r\n\r\nSource: `F:\\` (7200 RPM HDD), Output: `D:\\` (5400 RPM HDD). 3+ runs averaged.\r\n\r\n| Game | Pre-Refactor | Post-Refactor | Improvement |\r\n|------|-------------|---------------|-------------|\r\n| RHF | 11.4s | 10.8s | -0.6s (-5%) |\r\n| MKWii | ~26s | ~20s | -6s (-23%) |\r\n| SSBB | ~1m10s | ~1m01s | -9s (-13%) |\r\n\r\nOutput files are byte-identical. Improvement comes from the single-pass writer (Bundle D).\r\n\r\n## NKit API Spec\r\n\r\n### Design Goals\r\n- Format-agnostic: NKit v2 headers attach to WBFS, CISO, RVZ, and potentially any disc format\r\n- Follows Dolphin conventions: `BigEndianValue`, `AsWritableU8Span`, `std::optional`, `static_assert` on structs\r\n- Clean separation: NKit knows its own format and hashing requirements, callers don't\r\n- Matches @phire's review feedback (Comments 1-6, 17)\r\n\r\n### File Location\r\n`Source/Core/DiscIO/NKitHeader.h` and `Source/Core/DiscIO/NKitHeader.cpp`\r\n\r\nAll in `namespace DiscIO::NKit`.\r\n\r\n`HEADER_OFFSET` (0x10000) is the standard location for WBFS. Other formats may use different offsets - the offset is passed by the caller as I do not know if this holds true or not.\r\n@nanook can you confirm how NKit for other formats works?\r\n\r\nNote: DiscIO does not currently overload bitwise operators for enums. We added them for `NKit::Flags` since the flags are inherently bitwise.\r\n\r\n### Hashing\r\n\r\n```cpp\r\n// Compute all NKit v2 digests (SHA1, CRC32, MD5, XXHash64) over the full disc data.\r\n// This reads the entire disc sequentially.\r\nDigests ComputeDigests(BlobReader* reader, u64 disc_size);\r\n```\r\n\r\n- NKit owns the hashing logic since it defines which hashes are needed\r\n- Callers who already computed hashes during conversion can skip this and set `Info::digests` directly\r\n- Reads disc in chunks, updates all 4 hash contexts in parallel (single pass)\r\n\r\n## Deferred\r\n\r\nDual-layer WBFS file splitting (`.wbfs` + `.wbf1` for FAT32) - not investigated yet, separate PR as I do not have the necessary knowledge yet to implement.\r\n\r\n## Questions\r\n\r\n1. **NKit header offset:** `0x10000` is standard for WBFS. Does this differ for other formats NKit supports (CISO, RVZ)?\r\n\r\n2. **Namespace:** NKit API is under `DiscIO::NKit`. Is a nested namespace acceptable here?\r\n\r\n3. **BigEndianValue vs manual swap:** NKit structs use `BigEndianValue`, WIA/RVZ structs use manual `swap32()`/`swap64()`. Should these be consistent, or is the difference fine since NKit is a new file?\r\n\r\n4. **Hashing ownership:** NKit owns `ComputeDigests` since it defines which hashes are needed. The writer computes inline for performance and passes results directly. Is this separation reasonable?\r\n\r\n5. **Lossy conversion warning:** We show a soft warning and relaxed the asserts from `== Accurate` to `== Accurate || == UpperBound` in all 4 converters (ConvertToPlain, ConvertToGCZ, ConvertToWIAOrRVZ, ConvertToWBFS) to allow legacy WBFS and CISO conversion. Is this the right approach, or would you prefer a different gate?\r\n", 'raw': {'action': 'created', 'issue': {'url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/14731', 'repository_url': 'https://api.github.com/repos/dolphin-emu/dolphin', 'labels_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/14731/labels{/name}', 'comments_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/14731/comments', 'events_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/14731/events', 'html_url': 'https://github.com/dolphin-emu/dolphin/pull/14731', 'id': 4888393904, 'node_id': 'PR_kwDOALCn2M7x0I-2', 'number': 14731, 'title': 'Convert To WBFS Support', 'user': {'login': 'thethiny', 'id': 6018214, 'node_id': 'MDQ6VXNlcjYwMTgyMTQ=', 'avatar_url': 'https://avatars.githubusercontent.com/u/6018214?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/thethiny', 'html_url': 'https://github.com/thethiny', 'followers_url': 'https://api.github.com/users/thethiny/followers', 'following_url': 'https://api.github.com/users/thethiny/following{/other_user}', 'gists_url': 'https://api.github.com/users/thethiny/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/thethiny/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/thethiny/subscriptions', 'organizations_url': 'https://api.github.com/users/thethiny/orgs', 'repos_url': 'https://api.github.com/users/thethiny/repos', 'events_url': 'https://api.github.com/users/thethiny/events{/privacy}', 'received_events_url': 'https://api.github.com/users/thethiny/received_events', 'type': 'User', 'user_view_type': 'public', 'site_admin': False}, 'labels': [], 'state': 'open', 'locked': False, 'assignees': [], 'milestone': None, 'comments': 39, 'created_at': '2026-07-15T01:16:25Z', 'updated_at': '2026-07-18T20:15:22Z', 'closed_at': None, 'assignee': None, 'author_association': 'NONE', 'issue_field_values': [], 'type': None, 'active_lock_reason': None, 'draft': False, 'pull_request': {'url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/14731', 'html_url': 'https://github.com/dolphin-emu/dolphin/pull/14731', 'diff_url': 'https://github.com/dolphin-emu/dolphin/pull/14731.diff', 'patch_url': 'https://github.com/dolphin-emu/dolphin/pull/14731.patch', 'merged_at': None}, 'body': "This PR introduces Conversion **to** WBFS support. WBFS is the format that is used by USB Loaders on a real Wii device.\r\n\r\n## Design decisions & hardcoded values\r\nThe writer uses fixed sector sizes that match what [libwbfs (the reference implementation by kwiirk)](https://github.com/kwiirk/wbfs/blob/master/libwbfs/libwbfs.c#L128-L134) computes for a standard single-layer Wii disc. These 2 hardcodes are stable and work correctly across all my testings.\r\n- HD sector shift: 9 (512 bytes)\r\n- WBFS sector shift: 21 (2 MiB)\r\nThese are not configurable via the UI. All existing WBFS tools use these values, and since the aim is to support USB Loaders then this has been tested and it is working on a real Wii.\r\n\r\nConverting from WBFS is not enabled. The existing `WbfsFileReader` reports `DataSizeType::UpperBound`, and `ShouldAllowConversion()` requires `Accurate`. I am able to support this but since it was hardcoded by the Dolphin team I thought a discussion is warranted.\r\n\r\n## Testing\r\n- Verified with DolphinTool header and DolphinTool verify\r\n- Verified with wit FILETYPE and wit DUMP (Wiimm's ISO Tools recognizes valid WBFS structure, partitions, encryption)\r\n- Tested ISO to WBFS and RVZ to WBFS conversions\r\n- Output file sizes match Wii Backup Manager when scrubbing is enabled (~0.1% difference), works when scrubbing is disabled.\r\n- Output WBFS files play correctly in Dolphin\r\n- Output WBFS files play correctly on a real Wii using USB Loader GX e25c4f3\r\n", 'reactions': {'url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/14731/reactions', 'total_count': 2, '+1': 2, '-1': 0, 'laugh': 0, 'hooray': 0, 'confused': 0, 'heart': 0, 'rocket': 0, 'eyes': 0}, 'timeline_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/14731/timeline', 'performed_via_github_app': None, 'state_reason': None}, 'comment': {'url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/comments/5012766235', 'html_url': 'https://github.com/dolphin-emu/dolphin/pull/14731#issuecomment-5012766235', 'issue_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/14731', 'id': 5012766235, 'node_id': 'IC_kwDOALCn2M8AAAABKsi-Gw', 'user': {'login': 'thethiny', 'id': 6018214, 'node_id': 'MDQ6VXNlcjYwMTgyMTQ=', 'avatar_url': 'https://avatars.githubusercontent.com/u/6018214?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/thethiny', 'html_url': 'https://github.com/thethiny', 'followers_url': 'https://api.github.com/users/thethiny/followers', 'following_url': 'https://api.github.com/users/thethiny/following{/other_user}', 'gists_url': 'https://api.github.com/users/thethiny/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/thethiny/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/thethiny/subscriptions', 'organizations_url': 'https://api.github.com/users/thethiny/orgs', 'repos_url': 'https://api.github.com/users/thethiny/repos', 'events_url': 'https://api.github.com/users/thethiny/events{/privacy}', 'received_events_url': 'https://api.github.com/users/thethiny/received_events', 'type': 'User', 'user_view_type': 'public', 'site_admin': False}, 'created_at': '2026-07-18T20:15:22Z', 'updated_at': '2026-07-18T20:15:22Z', 'body': "Pushed commits addressing the code review feedback. Here's what changed and what's still open.\r\n\r\n## Commits\r\n\r\n**Bundle B: Skip disc-level junk checks for partition data**\r\nDisc-level zero and LFG junk checks now only run on non-partition regions. Partition data is encrypted and can never match these patterns.\r\n\r\n**Bundle A: Code quality fixes**\r\nRemoved redundant buffer zeroing, cast `sz` to `size_t` once, skip junk check when sector is already zero, use `std::ranges::find_if` for partition lookup.\r\n\r\n**Bundle D: Single-pass writer**\r\nMerged scan and write into a single loop - used sectors are written during the scan, headers are written by seeking back at the end. Halves disc I/O.\r\n\r\n**Bundle F2: Use Volume::Read for partition junk checks (writer)**\r\nWriter now uses `Volume::Read` for decrypted partition data instead of manual AES. Format-agnostic - avoids encrypt-then-decrypt round-trips for WIA/RVZ input.\r\n\r\n**Bundle F1: Simplify ReadWiiDecrypted (reader)**\r\n`SupportsReadWiiDecrypted` now returns true only for non-stored blocks (wlba == 0). For stored blocks, VolumeWii handles decryption through the normal `Read()` path.\r\n\r\n**Bundle C: NKit header refactor**\r\nMoved NKit code into standalone `NKitHeader.h/cpp` under `DiscIO::NKit`. Packed structs with `BigEndianValue`, `NKit::Flags` enum from Nanook's full spec, Key field corrected to `u8 key_length + u8 key_type`. Future-facing `ComputeDigests` and `Verify` API included but not yet called.\r\n\r\n**Lossy WBFS/CISO conversion warning**\r\nSoft warning when converting FROM `DataSizeType::UpperBound` files. Asserts relaxed to `== Accurate || == UpperBound` in all 4 converters. `ShouldAllowConversion` updated.\r\n\r\n**Cleanup**\r\nRemoved dead code (`m_wbfs_sector_count`, `m_nkit_disc_size`), renamed to NKit terminology (`gap_type`, `IsGapJunk`), dynamic `WriteHeader` size, deduplicated read parsers, added `mbedtls_md5_free` on all return paths.\r\n\r\n## Known Limitation\r\n\r\n`ReadWiiDecrypted` still contains manual AES decryption for stored blocks because `VolumeWii::EncryptGroup` calls it directly without checking `SupportsReadWiiDecrypted`. Fixing this would require modifying shared `VolumeWii` code - out of scope for this PR.\r\n\r\n## Benchmarks\r\n\r\nSource: `F:\\` (7200 RPM HDD), Output: `D:\\` (5400 RPM HDD). 3+ runs averaged.\r\n\r\n| Game | Pre-Refactor | Post-Refactor | Improvement |\r\n|------|-------------|---------------|-------------|\r\n| RHF | 11.4s | 10.8s | -0.6s (-5%) |\r\n| MKWii | ~26s | ~20s | -6s (-23%) |\r\n| SSBB | ~1m10s | ~1m01s | -9s (-13%) |\r\n\r\nOutput files are byte-identical. Improvement comes from the single-pass writer (Bundle D).\r\n\r\n## NKit API Spec\r\n\r\n### Design Goals\r\n- Format-agnostic: NKit v2 headers attach to WBFS, CISO, RVZ, and potentially any disc format\r\n- Follows Dolphin conventions: `BigEndianValue`, `AsWritableU8Span`, `std::optional`, `static_assert` on structs\r\n- Clean separation: NKit knows its own format and hashing requirements, callers don't\r\n- Matches @phire's review feedback (Comments 1-6, 17)\r\n\r\n### File Location\r\n`Source/Core/DiscIO/NKitHeader.h` and `Source/Core/DiscIO/NKitHeader.cpp`\r\n\r\nAll in `namespace DiscIO::NKit`.\r\n\r\n`HEADER_OFFSET` (0x10000) is the standard location for WBFS. Other formats may use different offsets - the offset is passed by the caller as I do not know if this holds true or not.\r\n@nanook can you confirm how NKit for other formats works?\r\n\r\nNote: DiscIO does not currently overload bitwise operators for enums. We added them for `NKit::Flags` since the flags are inherently bitwise.\r\n\r\n### Hashing\r\n\r\n```cpp\r\n// Compute all NKit v2 digests (SHA1, CRC32, MD5, XXHash64) over the full disc data.\r\n// This reads the entire disc sequentially.\r\nDigests ComputeDigests(BlobReader* reader, u64 disc_size);\r\n```\r\n\r\n- NKit owns the hashing logic since it defines which hashes are needed\r\n- Callers who already computed hashes during conversion can skip this and set `Info::digests` directly\r\n- Reads disc in chunks, updates all 4 hash contexts in parallel (single pass)\r\n\r\n## Deferred\r\n\r\nDual-layer WBFS file splitting (`.wbfs` + `.wbf1` for FAT32) - not investigated yet, separate PR as I do not have the necessary knowledge yet to implement.\r\n\r\n## Questions\r\n\r\n1. **NKit header offset:** `0x10000` is standard for WBFS. Does this differ for other formats NKit supports (CISO, RVZ)?\r\n\r\n2. **Namespace:** NKit API is under `DiscIO::NKit`. Is a nested namespace acceptable here?\r\n\r\n3. **BigEndianValue vs manual swap:** NKit structs use `BigEndianValue`, WIA/RVZ structs use manual `swap32()`/`swap64()`. Should these be consistent, or is the difference fine since NKit is a new file?\r\n\r\n4. **Hashing ownership:** NKit owns `ComputeDigests` since it defines which hashes are needed. The writer computes inline for performance and passes results directly. Is this separation reasonable?\r\n\r\n5. **Lossy conversion warning:** We show a soft warning and relaxed the asserts from `== Accurate` to `== Accurate || == UpperBound` in all 4 converters (ConvertToPlain, ConvertToGCZ, ConvertToWIAOrRVZ, ConvertToWBFS) to allow legacy WBFS and CISO conversion. Is this the right approach, or would you prefer a different gate?\r\n", 'author_association': 'NONE', 'reactions': {'url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/comments/5012766235/reactions', 'total_count': 0, '+1': 0, '-1': 0, 'laugh': 0, 'hooray': 0, 'confused': 0, 'heart': 0, 'rocket': 0, 'eyes': 0}, 'performed_via_github_app': None, 'minimized': None}, 'repository': {'id': 11577304, 'node_id': 'MDEwOlJlcG9zaXRvcnkxMTU3NzMwNA==', 'name': 'dolphin', 'full_name': 'dolphin-emu/dolphin', 'private': False, 'owner': {'login': 'dolphin-emu', 'id': 5050316, 'node_id': 'MDEyOk9yZ2FuaXphdGlvbjUwNTAzMTY=', 'avatar_url': 'https://avatars.githubusercontent.com/u/5050316?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/dolphin-emu', 'html_url': 'https://github.com/dolphin-emu', 'followers_url': 'https://api.github.com/users/dolphin-emu/followers', 'following_url': 'https://api.github.com/users/dolphin-emu/following{/other_user}', 'gists_url': 'https://api.github.com/users/dolphin-emu/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/dolphin-emu/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/dolphin-emu/subscriptions', 'organizations_url': 'https://api.github.com/users/dolphin-emu/orgs', 'repos_url': 'https://api.github.com/users/dolphin-emu/repos', 'events_url': 'https://api.github.com/users/dolphin-emu/events{/privacy}', 'received_events_url': 'https://api.github.com/users/dolphin-emu/received_events', 'type': 'Organization', 'user_view_type': 'public', 'site_admin': False}, 'html_url': 'https://github.com/dolphin-emu/dolphin', 'description': 'Dolphin is a GameCube / Wii emulator, allowing you to play games for these two platforms on PC with improvements.', 'fork': False, 'url': 'https://api.github.com/repos/dolphin-emu/dolphin', 'forks_url': 'https://api.github.com/repos/dolphin-emu/dolphin/forks', 'keys_url': 'https://api.github.com/repos/dolphin-emu/dolphin/keys{/key_id}', 'collaborators_url': 'https://api.github.com/repos/dolphin-emu/dolphin/collaborators{/collaborator}', 'teams_url': 'https://api.github.com/repos/dolphin-emu/dolphin/teams', 'hooks_url': 'https://api.github.com/repos/dolphin-emu/dolphin/hooks', 'issue_events_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/events{/number}', 'events_url': 'https://api.github.com/repos/dolphin-emu/dolphin/events', 'assignees_url': 'https://api.github.com/repos/dolphin-emu/dolphin/assignees{/user}', 'branches_url': 'https://api.github.com/repos/dolphin-emu/dolphin/branches{/branch}', 'tags_url': 'https://api.github.com/repos/dolphin-emu/dolphin/tags', 'blobs_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/blobs{/sha}', 'git_tags_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/tags{/sha}', 'git_refs_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/refs{/sha}', 'trees_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/trees{/sha}', 'statuses_url': 'https://api.github.com/repos/dolphin-emu/dolphin/statuses/{sha}', 'languages_url': 'https://api.github.com/repos/dolphin-emu/dolphin/languages', 'stargazers_url': 'https://api.github.com/repos/dolphin-emu/dolphin/stargazers', 'contributors_url': 'https://api.github.com/repos/dolphin-emu/dolphin/contributors', 'subscribers_url': 'https://api.github.com/repos/dolphin-emu/dolphin/subscribers', 'subscription_url': 'https://api.github.com/repos/dolphin-emu/dolphin/subscription', 'commits_url': 'https://api.github.com/repos/dolphin-emu/dolphin/commits{/sha}', 'git_commits_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/commits{/sha}', 'comments_url': 'https://api.github.com/repos/dolphin-emu/dolphin/comments{/number}', 'issue_comment_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/comments{/number}', 'contents_url': 'https://api.github.com/repos/dolphin-emu/dolphin/contents/{+path}', 'compare_url': 'https://api.github.com/repos/dolphin-emu/dolphin/compare/{base}...{head}', 'merges_url': 'https://api.github.com/repos/dolphin-emu/dolphin/merges', 'archive_url': 'https://api.github.com/repos/dolphin-emu/dolphin/{archive_format}{/ref}', 'downloads_url': 'https://api.github.com/repos/dolphin-emu/dolphin/downloads', 'issues_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues{/number}', 'pulls_url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls{/number}', 'milestones_url': 'https://api.github.com/repos/dolphin-emu/dolphin/milestones{/number}', 'notifications_url': 'https://api.github.com/repos/dolphin-emu/dolphin/notifications{?since,all,participating}', 'labels_url': 'https://api.github.com/repos/dolphin-emu/dolphin/labels{/name}', 'releases_url': 'https://api.github.com/repos/dolphin-emu/dolphin/releases{/id}', 'deployments_url': 'https://api.github.com/repos/dolphin-emu/dolphin/deployments', 'created_at': '2013-07-22T09:07:57Z', 'updated_at': '2026-07-18T18:44:16Z', 'pushed_at': '2026-07-18T10:34:54Z', 'git_url': 'git://github.com/dolphin-emu/dolphin.git', 'ssh_url': 'git@github.com:dolphin-emu/dolphin.git', 'clone_url': 'https://github.com/dolphin-emu/dolphin.git', 'svn_url': 'https://github.com/dolphin-emu/dolphin', 'homepage': 'https://dolphin-emu.org', 'size': 558448, 'stargazers_count': 15272, 'watchers_count': 15272, 'language': 'C++', 'has_issues': False, 'has_projects': False, 'has_downloads': True, 'has_wiki': True, 'has_pages': False, 'has_discussions': False, 'forks_count': 3161, 'mirror_url': None, 'archived': False, 'disabled': False, 'open_issues_count': 446, 'license': {'key': 'other', 'name': 'Other', 'spdx_id': 'NOASSERTION', 'url': None, 'node_id': 'MDc6TGljZW5zZTA='}, 'allow_forking': True, 'is_template': False, 'web_commit_signoff_required': False, 'has_pull_requests': True, 'pull_request_creation_policy': 'all', 'topics': ['cpp', 'emulation', 'emulator', 'gamecube', 'wii'], 'visibility': 'public', 'forks': 3161, 'open_issues': 446, 'watchers': 15272, 'default_branch': 'master', 'custom_properties': {}}, 'organization': {'login': 'dolphin-emu', 'id': 5050316, 'node_id': 'MDEyOk9yZ2FuaXphdGlvbjUwNTAzMTY=', 'url': 'https://api.github.com/orgs/dolphin-emu', 'repos_url': 'https://api.github.com/orgs/dolphin-emu/repos', 'events_url': 'https://api.github.com/orgs/dolphin-emu/events', 'hooks_url': 'https://api.github.com/orgs/dolphin-emu/hooks', 'issues_url': 'https://api.github.com/orgs/dolphin-emu/issues', 'members_url': 'https://api.github.com/orgs/dolphin-emu/members{/member}', 'public_members_url': 'https://api.github.com/orgs/dolphin-emu/public_members{/member}', 'avatar_url': 'https://avatars.githubusercontent.com/u/5050316?v=4', 'description': ''}, 'sender': {'login': 'thethiny', 'id': 6018214, 'node_id': 'MDQ6VXNlcjYwMTgyMTQ=', 'avatar_url': 'https://avatars.githubusercontent.com/u/6018214?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/thethiny', 'html_url': 'https://github.com/thethiny', 'followers_url': 'https://api.github.com/users/thethiny/followers', 'following_url': 'https://api.github.com/users/thethiny/following{/other_user}', 'gists_url': 'https://api.github.com/users/thethiny/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/thethiny/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/thethiny/subscriptions', 'organizations_url': 'https://api.github.com/users/thethiny/orgs', 'repos_url': 'https://api.github.com/users/thethiny/repos', 'events_url': 'https://api.github.com/users/thethiny/events{/privacy}', 'received_events_url': 'https://api.github.com/users/thethiny/received_events', 'type': 'User', 'user_view_type': 'public', 'site_admin': False}, 'installation': {'id': 35437981, 'node_id': 'MDIzOkludGVncmF0aW9uSW5zdGFsbGF0aW9uMzU0Mzc5ODE='}}, 'type': 'gh_issue_comment'}
2026-07-18T04:10:19.869180	{'source': 'ghhookparser', 'repo': 'dolphin-emu/dolphin', 'author': 'thethiny', 'action': 'created', 'id': 14731, 'title': 'Convert To WBFS Support', 'url': 'https://github.com/dolphin-emu/dolphin/pull/14731#issuecomment-5009849308', 'safe_author': False, 'body': "I addressed your review, and will proceed with the changes. Meanwhile, I've also confirmed with @Nanook over at Discord that Jakers seems to be working as intended in the current implementation.\r\n\r\n\r\n# Jakers! Kart Racing - Lossless Round-Trip Test\r\n\r\nGame: Jakers! Kart Racing (Europe) (En,Fr,De,Es,It,Sv,No,Da,Fi)\r\nGame ID: SJ3PNL\r\nClaim: This game has 1 bit of invalid junk beneath valid encryption\r\n\r\n## Redump Reference\r\n\r\n| Sectors | Size | CRC-32 | MD5 | SHA-1 |\r\n|---------|------|--------|-----|-------|\r\n| 2294912 | 4,699,979,776 | `528d7a25` | `a1be405079f67faf7b8799a857c897d0` | `8a0ea595460e4e06829e23064db01cb5a6511269` |\r\n\r\n## Path 1: ISO -> WBFS -> RVZ -> ISO\r\n\r\n| Step | Format | SHA-1 | Redump Match |\r\n|------|--------|-------|--------------|\r\n| Original | ISO | `8a0ea595460e4e06829e23064db01cb5a6511269` | ✅ |\r\n| ISO -> WBFS | WBFS | `27bd0a859205d5bb825d4a8ecf0521fd900c38bf` | - |\r\n| WBFS -> RVZ | RVZ | `3a3be5d5fd53868485e5a67ae7ba03e48055cc65` | - |\r\n| RVZ -> ISO | ISO | `8a0ea595460e4e06829e23064db01cb5a6511269` | ✅ |\r\n\r\n## Path 2: ISO -> RVZ -> WBFS -> ISO\r\n\r\n| Step | Format | SHA-1 | Redump Match |\r\n|------|--------|-------|--------------|\r\n| Original | ISO | `8a0ea595460e4e06829e23064db01cb5a6511269` | ✅ |\r\n| ISO -> RVZ | RVZ | `3a3be5d5fd53868485e5a67ae7ba03e48055cc65` | - |\r\n| RVZ -> WBFS | WBFS | `27bd0a859205d5bb825d4a8ecf0521fd900c38bf` | - |\r\n| WBFS -> ISO | ISO | `8a0ea595460e4e06829e23064db01cb5a6511269` | ✅ |\r\n\r\n## nod Verification\r\n\r\n```\r\nRedump: Jakers! Kart Racing (Europe) (En,Fr,De,Es,It,Sv,No,Da,Fi) ✅\r\nCRC32 : 528d7a25 ✅\r\nSHA-1 : 8a0ea595460e4e06829e23064db01cb5a6511269 ✅\r\nXXH64 : 03ef6ef71bec7556 ✅\r\n```\r\n\r\n", 'raw': {'action': 'created', 'issue': {'url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/14731', 'repository_url': 'https://api.github.com/repos/dolphin-emu/dolphin', 'labels_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/14731/labels{/name}', 'comments_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/14731/comments', 'events_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/14731/events', 'html_url': 'https://github.com/dolphin-emu/dolphin/pull/14731', 'id': 4888393904, 'node_id': 'PR_kwDOALCn2M7x0I-2', 'number': 14731, 'title': 'Convert To WBFS Support', 'user': {'login': 'thethiny', 'id': 6018214, 'node_id': 'MDQ6VXNlcjYwMTgyMTQ=', 'avatar_url': 'https://avatars.githubusercontent.com/u/6018214?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/thethiny', 'html_url': 'https://github.com/thethiny', 'followers_url': 'https://api.github.com/users/thethiny/followers', 'following_url': 'https://api.github.com/users/thethiny/following{/other_user}', 'gists_url': 'https://api.github.com/users/thethiny/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/thethiny/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/thethiny/subscriptions', 'organizations_url': 'https://api.github.com/users/thethiny/orgs', 'repos_url': 'https://api.github.com/users/thethiny/repos', 'events_url': 'https://api.github.com/users/thethiny/events{/privacy}', 'received_events_url': 'https://api.github.com/users/thethiny/received_events', 'type': 'User', 'user_view_type': 'public', 'site_admin': False}, 'labels': [], 'state': 'open', 'locked': False, 'assignees': [], 'milestone': None, 'comments': 38, 'created_at': '2026-07-15T01:16:25Z', 'updated_at': '2026-07-18T04:10:18Z', 'closed_at': None, 'assignee': None, 'author_association': 'NONE', 'issue_field_values': [], 'type': None, 'active_lock_reason': None, 'draft': False, 'pull_request': {'url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/14731', 'html_url': 'https://github.com/dolphin-emu/dolphin/pull/14731', 'diff_url': 'https://github.com/dolphin-emu/dolphin/pull/14731.diff', 'patch_url': 'https://github.com/dolphin-emu/dolphin/pull/14731.patch', 'merged_at': None}, 'body': "This PR introduces Conversion **to** WBFS support. WBFS is the format that is used by USB Loaders on a real Wii device.\r\n\r\n## Design decisions & hardcoded values\r\nThe writer uses fixed sector sizes that match what [libwbfs (the reference implementation by kwiirk)](https://github.com/kwiirk/wbfs/blob/master/libwbfs/libwbfs.c#L128-L134) computes for a standard single-layer Wii disc. These 2 hardcodes are stable and work correctly across all my testings.\r\n- HD sector shift: 9 (512 bytes)\r\n- WBFS sector shift: 21 (2 MiB)\r\nThese are not configurable via the UI. All existing WBFS tools use these values, and since the aim is to support USB Loaders then this has been tested and it is working on a real Wii.\r\n\r\nConverting from WBFS is not enabled. The existing `WbfsFileReader` reports `DataSizeType::UpperBound`, and `ShouldAllowConversion()` requires `Accurate`. I am able to support this but since it was hardcoded by the Dolphin team I thought a discussion is warranted.\r\n\r\n## Testing\r\n- Verified with DolphinTool header and DolphinTool verify\r\n- Verified with wit FILETYPE and wit DUMP (Wiimm's ISO Tools recognizes valid WBFS structure, partitions, encryption)\r\n- Tested ISO to WBFS and RVZ to WBFS conversions\r\n- Output file sizes match Wii Backup Manager when scrubbing is enabled (~0.1% difference), works when scrubbing is disabled.\r\n- Output WBFS files play correctly in Dolphin\r\n- Output WBFS files play correctly on a real Wii using USB Loader GX e25c4f3\r\n", 'reactions': {'url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/14731/reactions', 'total_count': 2, '+1': 2, '-1': 0, 'laugh': 0, 'hooray': 0, 'confused': 0, 'heart': 0, 'rocket': 0, 'eyes': 0}, 'timeline_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/14731/timeline', 'performed_via_github_app': None, 'state_reason': None}, 'comment': {'url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/comments/5009849308', 'html_url': 'https://github.com/dolphin-emu/dolphin/pull/14731#issuecomment-5009849308', 'issue_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/14731', 'id': 5009849308, 'node_id': 'IC_kwDOALCn2M8AAAABKpw73A', 'user': {'login': 'thethiny', 'id': 6018214, 'node_id': 'MDQ6VXNlcjYwMTgyMTQ=', 'avatar_url': 'https://avatars.githubusercontent.com/u/6018214?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/thethiny', 'html_url': 'https://github.com/thethiny', 'followers_url': 'https://api.github.com/users/thethiny/followers', 'following_url': 'https://api.github.com/users/thethiny/following{/other_user}', 'gists_url': 'https://api.github.com/users/thethiny/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/thethiny/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/thethiny/subscriptions', 'organizations_url': 'https://api.github.com/users/thethiny/orgs', 'repos_url': 'https://api.github.com/users/thethiny/repos', 'events_url': 'https://api.github.com/users/thethiny/events{/privacy}', 'received_events_url': 'https://api.github.com/users/thethiny/received_events', 'type': 'User', 'user_view_type': 'public', 'site_admin': False}, 'created_at': '2026-07-18T04:10:17Z', 'updated_at': '2026-07-18T04:10:17Z', 'body': "I addressed your review, and will proceed with the changes. Meanwhile, I've also confirmed with @Nanook over at Discord that Jakers seems to be working as intended in the current implementation.\r\n\r\n\r\n# Jakers! Kart Racing - Lossless Round-Trip Test\r\n\r\nGame: Jakers! Kart Racing (Europe) (En,Fr,De,Es,It,Sv,No,Da,Fi)\r\nGame ID: SJ3PNL\r\nClaim: This game has 1 bit of invalid junk beneath valid encryption\r\n\r\n## Redump Reference\r\n\r\n| Sectors | Size | CRC-32 | MD5 | SHA-1 |\r\n|---------|------|--------|-----|-------|\r\n| 2294912 | 4,699,979,776 | `528d7a25` | `a1be405079f67faf7b8799a857c897d0` | `8a0ea595460e4e06829e23064db01cb5a6511269` |\r\n\r\n## Path 1: ISO -> WBFS -> RVZ -> ISO\r\n\r\n| Step | Format | SHA-1 | Redump Match |\r\n|------|--------|-------|--------------|\r\n| Original | ISO | `8a0ea595460e4e06829e23064db01cb5a6511269` | ✅ |\r\n| ISO -> WBFS | WBFS | `27bd0a859205d5bb825d4a8ecf0521fd900c38bf` | - |\r\n| WBFS -> RVZ | RVZ | `3a3be5d5fd53868485e5a67ae7ba03e48055cc65` | - |\r\n| RVZ -> ISO | ISO | `8a0ea595460e4e06829e23064db01cb5a6511269` | ✅ |\r\n\r\n## Path 2: ISO -> RVZ -> WBFS -> ISO\r\n\r\n| Step | Format | SHA-1 | Redump Match |\r\n|------|--------|-------|--------------|\r\n| Original | ISO | `8a0ea595460e4e06829e23064db01cb5a6511269` | ✅ |\r\n| ISO -> RVZ | RVZ | `3a3be5d5fd53868485e5a67ae7ba03e48055cc65` | - |\r\n| RVZ -> WBFS | WBFS | `27bd0a859205d5bb825d4a8ecf0521fd900c38bf` | - |\r\n| WBFS -> ISO | ISO | `8a0ea595460e4e06829e23064db01cb5a6511269` | ✅ |\r\n\r\n## nod Verification\r\n\r\n```\r\nRedump: Jakers! Kart Racing (Europe) (En,Fr,De,Es,It,Sv,No,Da,Fi) ✅\r\nCRC32 : 528d7a25 ✅\r\nSHA-1 : 8a0ea595460e4e06829e23064db01cb5a6511269 ✅\r\nXXH64 : 03ef6ef71bec7556 ✅\r\n```\r\n\r\n", 'author_association': 'NONE', 'reactions': {'url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/comments/5009849308/reactions', 'total_count': 0, '+1': 0, '-1': 0, 'laugh': 0, 'hooray': 0, 'confused': 0, 'heart': 0, 'rocket': 0, 'eyes': 0}, 'performed_via_github_app': None, 'minimized': None}, 'repository': {'id': 11577304, 'node_id': 'MDEwOlJlcG9zaXRvcnkxMTU3NzMwNA==', 'name': 'dolphin', 'full_name': 'dolphin-emu/dolphin', 'private': False, 'owner': {'login': 'dolphin-emu', 'id': 5050316, 'node_id': 'MDEyOk9yZ2FuaXphdGlvbjUwNTAzMTY=', 'avatar_url': 'https://avatars.githubusercontent.com/u/5050316?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/dolphin-emu', 'html_url': 'https://github.com/dolphin-emu', 'followers_url': 'https://api.github.com/users/dolphin-emu/followers', 'following_url': 'https://api.github.com/users/dolphin-emu/following{/other_user}', 'gists_url': 'https://api.github.com/users/dolphin-emu/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/dolphin-emu/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/dolphin-emu/subscriptions', 'organizations_url': 'https://api.github.com/users/dolphin-emu/orgs', 'repos_url': 'https://api.github.com/users/dolphin-emu/repos', 'events_url': 'https://api.github.com/users/dolphin-emu/events{/privacy}', 'received_events_url': 'https://api.github.com/users/dolphin-emu/received_events', 'type': 'Organization', 'user_view_type': 'public', 'site_admin': False}, 'html_url': 'https://github.com/dolphin-emu/dolphin', 'description': 'Dolphin is a GameCube / Wii emulator, allowing you to play games for these two platforms on PC with improvements.', 'fork': False, 'url': 'https://api.github.com/repos/dolphin-emu/dolphin', 'forks_url': 'https://api.github.com/repos/dolphin-emu/dolphin/forks', 'keys_url': 'https://api.github.com/repos/dolphin-emu/dolphin/keys{/key_id}', 'collaborators_url': 'https://api.github.com/repos/dolphin-emu/dolphin/collaborators{/collaborator}', 'teams_url': 'https://api.github.com/repos/dolphin-emu/dolphin/teams', 'hooks_url': 'https://api.github.com/repos/dolphin-emu/dolphin/hooks', 'issue_events_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/events{/number}', 'events_url': 'https://api.github.com/repos/dolphin-emu/dolphin/events', 'assignees_url': 'https://api.github.com/repos/dolphin-emu/dolphin/assignees{/user}', 'branches_url': 'https://api.github.com/repos/dolphin-emu/dolphin/branches{/branch}', 'tags_url': 'https://api.github.com/repos/dolphin-emu/dolphin/tags', 'blobs_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/blobs{/sha}', 'git_tags_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/tags{/sha}', 'git_refs_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/refs{/sha}', 'trees_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/trees{/sha}', 'statuses_url': 'https://api.github.com/repos/dolphin-emu/dolphin/statuses/{sha}', 'languages_url': 'https://api.github.com/repos/dolphin-emu/dolphin/languages', 'stargazers_url': 'https://api.github.com/repos/dolphin-emu/dolphin/stargazers', 'contributors_url': 'https://api.github.com/repos/dolphin-emu/dolphin/contributors', 'subscribers_url': 'https://api.github.com/repos/dolphin-emu/dolphin/subscribers', 'subscription_url': 'https://api.github.com/repos/dolphin-emu/dolphin/subscription', 'commits_url': 'https://api.github.com/repos/dolphin-emu/dolphin/commits{/sha}', 'git_commits_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/commits{/sha}', 'comments_url': 'https://api.github.com/repos/dolphin-emu/dolphin/comments{/number}', 'issue_comment_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/comments{/number}', 'contents_url': 'https://api.github.com/repos/dolphin-emu/dolphin/contents/{+path}', 'compare_url': 'https://api.github.com/repos/dolphin-emu/dolphin/compare/{base}...{head}', 'merges_url': 'https://api.github.com/repos/dolphin-emu/dolphin/merges', 'archive_url': 'https://api.github.com/repos/dolphin-emu/dolphin/{archive_format}{/ref}', 'downloads_url': 'https://api.github.com/repos/dolphin-emu/dolphin/downloads', 'issues_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues{/number}', 'pulls_url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls{/number}', 'milestones_url': 'https://api.github.com/repos/dolphin-emu/dolphin/milestones{/number}', 'notifications_url': 'https://api.github.com/repos/dolphin-emu/dolphin/notifications{?since,all,participating}', 'labels_url': 'https://api.github.com/repos/dolphin-emu/dolphin/labels{/name}', 'releases_url': 'https://api.github.com/repos/dolphin-emu/dolphin/releases{/id}', 'deployments_url': 'https://api.github.com/repos/dolphin-emu/dolphin/deployments', 'created_at': '2013-07-22T09:07:57Z', 'updated_at': '2026-07-18T01:56:22Z', 'pushed_at': '2026-07-15T20:58:02Z', 'git_url': 'git://github.com/dolphin-emu/dolphin.git', 'ssh_url': 'git@github.com:dolphin-emu/dolphin.git', 'clone_url': 'https://github.com/dolphin-emu/dolphin.git', 'svn_url': 'https://github.com/dolphin-emu/dolphin', 'homepage': 'https://dolphin-emu.org', 'size': 558444, 'stargazers_count': 15269, 'watchers_count': 15269, 'language': 'C++', 'has_issues': False, 'has_projects': False, 'has_downloads': True, 'has_wiki': True, 'has_pages': False, 'has_discussions': False, 'forks_count': 3162, 'mirror_url': None, 'archived': False, 'disabled': False, 'open_issues_count': 447, 'license': {'key': 'other', 'name': 'Other', 'spdx_id': 'NOASSERTION', 'url': None, 'node_id': 'MDc6TGljZW5zZTA='}, 'allow_forking': True, 'is_template': False, 'web_commit_signoff_required': False, 'has_pull_requests': True, 'pull_request_creation_policy': 'all', 'topics': ['cpp', 'emulation', 'emulator', 'gamecube', 'wii'], 'visibility': 'public', 'forks': 3162, 'open_issues': 447, 'watchers': 15269, 'default_branch': 'master', 'custom_properties': {}}, 'organization': {'login': 'dolphin-emu', 'id': 5050316, 'node_id': 'MDEyOk9yZ2FuaXphdGlvbjUwNTAzMTY=', 'url': 'https://api.github.com/orgs/dolphin-emu', 'repos_url': 'https://api.github.com/orgs/dolphin-emu/repos', 'events_url': 'https://api.github.com/orgs/dolphin-emu/events', 'hooks_url': 'https://api.github.com/orgs/dolphin-emu/hooks', 'issues_url': 'https://api.github.com/orgs/dolphin-emu/issues', 'members_url': 'https://api.github.com/orgs/dolphin-emu/members{/member}', 'public_members_url': 'https://api.github.com/orgs/dolphin-emu/public_members{/member}', 'avatar_url': 'https://avatars.githubusercontent.com/u/5050316?v=4', 'description': ''}, 'sender': {'login': 'thethiny', 'id': 6018214, 'node_id': 'MDQ6VXNlcjYwMTgyMTQ=', 'avatar_url': 'https://avatars.githubusercontent.com/u/6018214?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/thethiny', 'html_url': 'https://github.com/thethiny', 'followers_url': 'https://api.github.com/users/thethiny/followers', 'following_url': 'https://api.github.com/users/thethiny/following{/other_user}', 'gists_url': 'https://api.github.com/users/thethiny/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/thethiny/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/thethiny/subscriptions', 'organizations_url': 'https://api.github.com/users/thethiny/orgs', 'repos_url': 'https://api.github.com/users/thethiny/repos', 'events_url': 'https://api.github.com/users/thethiny/events{/privacy}', 'received_events_url': 'https://api.github.com/users/thethiny/received_events', 'type': 'User', 'user_view_type': 'public', 'site_admin': False}, 'installation': {'id': 35437981, 'node_id': 'MDIzOkludGVncmF0aW9uSW5zdGFsbGF0aW9uMzU0Mzc5ODE='}}, 'type': 'gh_issue_comment'}
2026-07-18T03:05:18.607399	{'source': 'ghhookparser', 'repo': 'dolphin-emu/dolphin', 'author': 'thethiny', 'action': 'created', 'id': 14731, 'title': 'Convert To WBFS Support', 'url': 'https://github.com/dolphin-emu/dolphin/pull/14731#issuecomment-5009649321', 'safe_author': False, 'body': '@phire thanks for your comments, I will address them all in the next comment. Meanwhile as I mentioned in the first commit, should this PR be broadened to include refactoring the file formats? Since lots of stuff seem to have been entangled with other formats and some core implementations are becoming shared.\r\n\r\nAlso, this is my vision for converting from GCZ/WBFS that is lossy.\r\n<img width="517" height="608" alt="image" src="https://github.com/user-attachments/assets/81c9519c-f8f6-4b96-96f9-baeeef6bcd02" />\r\nvs lossless \r\n<img width="517" height="554" alt="image" src="https://github.com/user-attachments/assets/e3c6a685-8926-45ec-b256-5276f05a197d" />\r\n', 'raw': {'action': 'created', 'issue': {'url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/14731', 'repository_url': 'https://api.github.com/repos/dolphin-emu/dolphin', 'labels_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/14731/labels{/name}', 'comments_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/14731/comments', 'events_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/14731/events', 'html_url': 'https://github.com/dolphin-emu/dolphin/pull/14731', 'id': 4888393904, 'node_id': 'PR_kwDOALCn2M7x0I-2', 'number': 14731, 'title': 'Convert To WBFS Support', 'user': {'login': 'thethiny', 'id': 6018214, 'node_id': 'MDQ6VXNlcjYwMTgyMTQ=', 'avatar_url': 'https://avatars.githubusercontent.com/u/6018214?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/thethiny', 'html_url': 'https://github.com/thethiny', 'followers_url': 'https://api.github.com/users/thethiny/followers', 'following_url': 'https://api.github.com/users/thethiny/following{/other_user}', 'gists_url': 'https://api.github.com/users/thethiny/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/thethiny/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/thethiny/subscriptions', 'organizations_url': 'https://api.github.com/users/thethiny/orgs', 'repos_url': 'https://api.github.com/users/thethiny/repos', 'events_url': 'https://api.github.com/users/thethiny/events{/privacy}', 'received_events_url': 'https://api.github.com/users/thethiny/received_events', 'type': 'User', 'user_view_type': 'public', 'site_admin': False}, 'labels': [], 'state': 'open', 'locked': False, 'assignees': [], 'milestone': None, 'comments': 37, 'created_at': '2026-07-15T01:16:25Z', 'updated_at': '2026-07-18T03:05:17Z', 'closed_at': None, 'assignee': None, 'author_association': 'NONE', 'issue_field_values': [], 'type': None, 'active_lock_reason': None, 'draft': False, 'pull_request': {'url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/14731', 'html_url': 'https://github.com/dolphin-emu/dolphin/pull/14731', 'diff_url': 'https://github.com/dolphin-emu/dolphin/pull/14731.diff', 'patch_url': 'https://github.com/dolphin-emu/dolphin/pull/14731.patch', 'merged_at': None}, 'body': "This PR introduces Conversion **to** WBFS support. WBFS is the format that is used by USB Loaders on a real Wii device.\r\n\r\n## Design decisions & hardcoded values\r\nThe writer uses fixed sector sizes that match what [libwbfs (the reference implementation by kwiirk)](https://github.com/kwiirk/wbfs/blob/master/libwbfs/libwbfs.c#L128-L134) computes for a standard single-layer Wii disc. These 2 hardcodes are stable and work correctly across all my testings.\r\n- HD sector shift: 9 (512 bytes)\r\n- WBFS sector shift: 21 (2 MiB)\r\nThese are not configurable via the UI. All existing WBFS tools use these values, and since the aim is to support USB Loaders then this has been tested and it is working on a real Wii.\r\n\r\nConverting from WBFS is not enabled. The existing `WbfsFileReader` reports `DataSizeType::UpperBound`, and `ShouldAllowConversion()` requires `Accurate`. I am able to support this but since it was hardcoded by the Dolphin team I thought a discussion is warranted.\r\n\r\n## Testing\r\n- Verified with DolphinTool header and DolphinTool verify\r\n- Verified with wit FILETYPE and wit DUMP (Wiimm's ISO Tools recognizes valid WBFS structure, partitions, encryption)\r\n- Tested ISO to WBFS and RVZ to WBFS conversions\r\n- Output file sizes match Wii Backup Manager when scrubbing is enabled (~0.1% difference), works when scrubbing is disabled.\r\n- Output WBFS files play correctly in Dolphin\r\n- Output WBFS files play correctly on a real Wii using USB Loader GX e25c4f3\r\n", 'reactions': {'url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/14731/reactions', 'total_count': 2, '+1': 2, '-1': 0, 'laugh': 0, 'hooray': 0, 'confused': 0, 'heart': 0, 'rocket': 0, 'eyes': 0}, 'timeline_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/14731/timeline', 'performed_via_github_app': None, 'state_reason': None}, 'comment': {'url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/comments/5009649321', 'html_url': 'https://github.com/dolphin-emu/dolphin/pull/14731#issuecomment-5009649321', 'issue_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/14731', 'id': 5009649321, 'node_id': 'IC_kwDOALCn2M8AAAABKpkuqQ', 'user': {'login': 'thethiny', 'id': 6018214, 'node_id': 'MDQ6VXNlcjYwMTgyMTQ=', 'avatar_url': 'https://avatars.githubusercontent.com/u/6018214?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/thethiny', 'html_url': 'https://github.com/thethiny', 'followers_url': 'https://api.github.com/users/thethiny/followers', 'following_url': 'https://api.github.com/users/thethiny/following{/other_user}', 'gists_url': 'https://api.github.com/users/thethiny/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/thethiny/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/thethiny/subscriptions', 'organizations_url': 'https://api.github.com/users/thethiny/orgs', 'repos_url': 'https://api.github.com/users/thethiny/repos', 'events_url': 'https://api.github.com/users/thethiny/events{/privacy}', 'received_events_url': 'https://api.github.com/users/thethiny/received_events', 'type': 'User', 'user_view_type': 'public', 'site_admin': False}, 'created_at': '2026-07-18T03:05:16Z', 'updated_at': '2026-07-18T03:05:16Z', 'body': '@phire thanks for your comments, I will address them all in the next comment. Meanwhile as I mentioned in the first commit, should this PR be broadened to include refactoring the file formats? Since lots of stuff seem to have been entangled with other formats and some core implementations are becoming shared.\r\n\r\nAlso, this is my vision for converting from GCZ/WBFS that is lossy.\r\n<img width="517" height="608" alt="image" src="https://github.com/user-attachments/assets/81c9519c-f8f6-4b96-96f9-baeeef6bcd02" />\r\nvs lossless \r\n<img width="517" height="554" alt="image" src="https://github.com/user-attachments/assets/e3c6a685-8926-45ec-b256-5276f05a197d" />\r\n', 'author_association': 'NONE', 'reactions': {'url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/comments/5009649321/reactions', 'total_count': 0, '+1': 0, '-1': 0, 'laugh': 0, 'hooray': 0, 'confused': 0, 'heart': 0, 'rocket': 0, 'eyes': 0}, 'performed_via_github_app': None, 'minimized': None}, 'repository': {'id': 11577304, 'node_id': 'MDEwOlJlcG9zaXRvcnkxMTU3NzMwNA==', 'name': 'dolphin', 'full_name': 'dolphin-emu/dolphin', 'private': False, 'owner': {'login': 'dolphin-emu', 'id': 5050316, 'node_id': 'MDEyOk9yZ2FuaXphdGlvbjUwNTAzMTY=', 'avatar_url': 'https://avatars.githubusercontent.com/u/5050316?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/dolphin-emu', 'html_url': 'https://github.com/dolphin-emu', 'followers_url': 'https://api.github.com/users/dolphin-emu/followers', 'following_url': 'https://api.github.com/users/dolphin-emu/following{/other_user}', 'gists_url': 'https://api.github.com/users/dolphin-emu/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/dolphin-emu/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/dolphin-emu/subscriptions', 'organizations_url': 'https://api.github.com/users/dolphin-emu/orgs', 'repos_url': 'https://api.github.com/users/dolphin-emu/repos', 'events_url': 'https://api.github.com/users/dolphin-emu/events{/privacy}', 'received_events_url': 'https://api.github.com/users/dolphin-emu/received_events', 'type': 'Organization', 'user_view_type': 'public', 'site_admin': False}, 'html_url': 'https://github.com/dolphin-emu/dolphin', 'description': 'Dolphin is a GameCube / Wii emulator, allowing you to play games for these two platforms on PC with improvements.', 'fork': False, 'url': 'https://api.github.com/repos/dolphin-emu/dolphin', 'forks_url': 'https://api.github.com/repos/dolphin-emu/dolphin/forks', 'keys_url': 'https://api.github.com/repos/dolphin-emu/dolphin/keys{/key_id}', 'collaborators_url': 'https://api.github.com/repos/dolphin-emu/dolphin/collaborators{/collaborator}', 'teams_url': 'https://api.github.com/repos/dolphin-emu/dolphin/teams', 'hooks_url': 'https://api.github.com/repos/dolphin-emu/dolphin/hooks', 'issue_events_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/events{/number}', 'events_url': 'https://api.github.com/repos/dolphin-emu/dolphin/events', 'assignees_url': 'https://api.github.com/repos/dolphin-emu/dolphin/assignees{/user}', 'branches_url': 'https://api.github.com/repos/dolphin-emu/dolphin/branches{/branch}', 'tags_url': 'https://api.github.com/repos/dolphin-emu/dolphin/tags', 'blobs_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/blobs{/sha}', 'git_tags_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/tags{/sha}', 'git_refs_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/refs{/sha}', 'trees_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/trees{/sha}', 'statuses_url': 'https://api.github.com/repos/dolphin-emu/dolphin/statuses/{sha}', 'languages_url': 'https://api.github.com/repos/dolphin-emu/dolphin/languages', 'stargazers_url': 'https://api.github.com/repos/dolphin-emu/dolphin/stargazers', 'contributors_url': 'https://api.github.com/repos/dolphin-emu/dolphin/contributors', 'subscribers_url': 'https://api.github.com/repos/dolphin-emu/dolphin/subscribers', 'subscription_url': 'https://api.github.com/repos/dolphin-emu/dolphin/subscription', 'commits_url': 'https://api.github.com/repos/dolphin-emu/dolphin/commits{/sha}', 'git_commits_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/commits{/sha}', 'comments_url': 'https://api.github.com/repos/dolphin-emu/dolphin/comments{/number}', 'issue_comment_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/comments{/number}', 'contents_url': 'https://api.github.com/repos/dolphin-emu/dolphin/contents/{+path}', 'compare_url': 'https://api.github.com/repos/dolphin-emu/dolphin/compare/{base}...{head}', 'merges_url': 'https://api.github.com/repos/dolphin-emu/dolphin/merges', 'archive_url': 'https://api.github.com/repos/dolphin-emu/dolphin/{archive_format}{/ref}', 'downloads_url': 'https://api.github.com/repos/dolphin-emu/dolphin/downloads', 'issues_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues{/number}', 'pulls_url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls{/number}', 'milestones_url': 'https://api.github.com/repos/dolphin-emu/dolphin/milestones{/number}', 'notifications_url': 'https://api.github.com/repos/dolphin-emu/dolphin/notifications{?since,all,participating}', 'labels_url': 'https://api.github.com/repos/dolphin-emu/dolphin/labels{/name}', 'releases_url': 'https://api.github.com/repos/dolphin-emu/dolphin/releases{/id}', 'deployments_url': 'https://api.github.com/repos/dolphin-emu/dolphin/deployments', 'created_at': '2013-07-22T09:07:57Z', 'updated_at': '2026-07-18T01:56:22Z', 'pushed_at': '2026-07-15T20:58:02Z', 'git_url': 'git://github.com/dolphin-emu/dolphin.git', 'ssh_url': 'git@github.com:dolphin-emu/dolphin.git', 'clone_url': 'https://github.com/dolphin-emu/dolphin.git', 'svn_url': 'https://github.com/dolphin-emu/dolphin', 'homepage': 'https://dolphin-emu.org', 'size': 558444, 'stargazers_count': 15269, 'watchers_count': 15269, 'language': 'C++', 'has_issues': False, 'has_projects': False, 'has_downloads': True, 'has_wiki': True, 'has_pages': False, 'has_discussions': False, 'forks_count': 3162, 'mirror_url': None, 'archived': False, 'disabled': False, 'open_issues_count': 447, 'license': {'key': 'other', 'name': 'Other', 'spdx_id': 'NOASSERTION', 'url': None, 'node_id': 'MDc6TGljZW5zZTA='}, 'allow_forking': True, 'is_template': False, 'web_commit_signoff_required': False, 'has_pull_requests': True, 'pull_request_creation_policy': 'all', 'topics': ['cpp', 'emulation', 'emulator', 'gamecube', 'wii'], 'visibility': 'public', 'forks': 3162, 'open_issues': 447, 'watchers': 15269, 'default_branch': 'master', 'custom_properties': {}}, 'organization': {'login': 'dolphin-emu', 'id': 5050316, 'node_id': 'MDEyOk9yZ2FuaXphdGlvbjUwNTAzMTY=', 'url': 'https://api.github.com/orgs/dolphin-emu', 'repos_url': 'https://api.github.com/orgs/dolphin-emu/repos', 'events_url': 'https://api.github.com/orgs/dolphin-emu/events', 'hooks_url': 'https://api.github.com/orgs/dolphin-emu/hooks', 'issues_url': 'https://api.github.com/orgs/dolphin-emu/issues', 'members_url': 'https://api.github.com/orgs/dolphin-emu/members{/member}', 'public_members_url': 'https://api.github.com/orgs/dolphin-emu/public_members{/member}', 'avatar_url': 'https://avatars.githubusercontent.com/u/5050316?v=4', 'description': ''}, 'sender': {'login': 'thethiny', 'id': 6018214, 'node_id': 'MDQ6VXNlcjYwMTgyMTQ=', 'avatar_url': 'https://avatars.githubusercontent.com/u/6018214?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/thethiny', 'html_url': 'https://github.com/thethiny', 'followers_url': 'https://api.github.com/users/thethiny/followers', 'following_url': 'https://api.github.com/users/thethiny/following{/other_user}', 'gists_url': 'https://api.github.com/users/thethiny/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/thethiny/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/thethiny/subscriptions', 'organizations_url': 'https://api.github.com/users/thethiny/orgs', 'repos_url': 'https://api.github.com/users/thethiny/repos', 'events_url': 'https://api.github.com/users/thethiny/events{/privacy}', 'received_events_url': 'https://api.github.com/users/thethiny/received_events', 'type': 'User', 'user_view_type': 'public', 'site_admin': False}, 'installation': {'id': 35437981, 'node_id': 'MDIzOkludGVncmF0aW9uSW5zdGFsbGF0aW9uMzU0Mzc5ODE='}}, 'type': 'gh_issue_comment'}
2026-07-17T22:28:58.036356	{'source': 'ghhookparser', 'repo': 'dolphin-emu/dolphin', 'author': 'thethiny', 'action': 'edited', 'id': 14731, 'title': 'Convert To WBFS Support', 'url': 'https://github.com/dolphin-emu/dolphin/pull/14731#issuecomment-5008087561', 'safe_author': False, 'body': "> Test Jakers as it has 1 bit of invalid junk beneath valid encryption\r\n\r\nAre we talking about Let's Explore or the Karting game? This is the first time I hear of this game in my life lol.\r\n\r\n> Also, you probably should be using dolphin's existing `MultithreadedCompressor` infrastructure, already used by RVZ and GCZ. Sure, lossless wbfs doesn't do any explicit compression, but removing junk counts as compression and multithreadding would certainly speed it up.\r\n>\r\n> Let me know if you need any help working out how to hook into that infrastructure.\r\n\r\nThanks for offering to help, I pushed my changes before I read this. I will look into it. Meanwhile are you able to confirm my commits based on my explanation above?\r\n\r\n", 'raw': {'action': 'edited', 'changes': {'body': {'from': "> Test Jakers as it has 1 bit of invalid junk beneath valid encryption\r\n\r\nAre we talking about Let's Explore or the Karting game? This is the first time I hear of this game in my life lol.\r\n\r\n> Also, you probably should be using dolphin's existing `MultithreadedCompressor` infrastructure, already used by RVZ and GCZ. Sure, lossless wbfs doesn't do any explicit compression, but removing junk counts as compression and multithreadding would certainly speed it up.\r\n> \r\n> Let me know if you need any help working out how to hook into that infrastructure.\r\nThanks for offering to help, I pushed my changes before I read this. I will look into it. Meanwhile are you able to confirm my commits based on my explanation above?\r\n\r\n"}}, 'issue': {'url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/14731', 'repository_url': 'https://api.github.com/repos/dolphin-emu/dolphin', 'labels_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/14731/labels{/name}', 'comments_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/14731/comments', 'events_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/14731/events', 'html_url': 'https://github.com/dolphin-emu/dolphin/pull/14731', 'id': 4888393904, 'node_id': 'PR_kwDOALCn2M7x0I-2', 'number': 14731, 'title': 'Convert To WBFS Support', 'user': {'login': 'thethiny', 'id': 6018214, 'node_id': 'MDQ6VXNlcjYwMTgyMTQ=', 'avatar_url': 'https://avatars.githubusercontent.com/u/6018214?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/thethiny', 'html_url': 'https://github.com/thethiny', 'followers_url': 'https://api.github.com/users/thethiny/followers', 'following_url': 'https://api.github.com/users/thethiny/following{/other_user}', 'gists_url': 'https://api.github.com/users/thethiny/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/thethiny/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/thethiny/subscriptions', 'organizations_url': 'https://api.github.com/users/thethiny/orgs', 'repos_url': 'https://api.github.com/users/thethiny/repos', 'events_url': 'https://api.github.com/users/thethiny/events{/privacy}', 'received_events_url': 'https://api.github.com/users/thethiny/received_events', 'type': 'User', 'user_view_type': 'public', 'site_admin': False}, 'labels': [], 'state': 'open', 'locked': False, 'assignees': [], 'milestone': None, 'comments': 36, 'created_at': '2026-07-15T01:16:25Z', 'updated_at': '2026-07-17T22:28:40Z', 'closed_at': None, 'assignee': None, 'author_association': 'NONE', 'issue_field_values': [], 'type': None, 'active_lock_reason': None, 'draft': False, 'pull_request': {'url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/14731', 'html_url': 'https://github.com/dolphin-emu/dolphin/pull/14731', 'diff_url': 'https://github.com/dolphin-emu/dolphin/pull/14731.diff', 'patch_url': 'https://github.com/dolphin-emu/dolphin/pull/14731.patch', 'merged_at': None}, 'body': "This PR introduces Conversion **to** WBFS support. WBFS is the format that is used by USB Loaders on a real Wii device.\r\n\r\n## Design decisions & hardcoded values\r\nThe writer uses fixed sector sizes that match what [libwbfs (the reference implementation by kwiirk)](https://github.com/kwiirk/wbfs/blob/master/libwbfs/libwbfs.c#L128-L134) computes for a standard single-layer Wii disc. These 2 hardcodes are stable and work correctly across all my testings.\r\n- HD sector shift: 9 (512 bytes)\r\n- WBFS sector shift: 21 (2 MiB)\r\nThese are not configurable via the UI. All existing WBFS tools use these values, and since the aim is to support USB Loaders then this has been tested and it is working on a real Wii.\r\n\r\nConverting from WBFS is not enabled. The existing `WbfsFileReader` reports `DataSizeType::UpperBound`, and `ShouldAllowConversion()` requires `Accurate`. I am able to support this but since it was hardcoded by the Dolphin team I thought a discussion is warranted.\r\n\r\n## Testing\r\n- Verified with DolphinTool header and DolphinTool verify\r\n- Verified with wit FILETYPE and wit DUMP (Wiimm's ISO Tools recognizes valid WBFS structure, partitions, encryption)\r\n- Tested ISO to WBFS and RVZ to WBFS conversions\r\n- Output file sizes match Wii Backup Manager when scrubbing is enabled (~0.1% difference), works when scrubbing is disabled.\r\n- Output WBFS files play correctly in Dolphin\r\n- Output WBFS files play correctly on a real Wii using USB Loader GX e25c4f3\r\n", 'reactions': {'url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/14731/reactions', 'total_count': 2, '+1': 2, '-1': 0, 'laugh': 0, 'hooray': 0, 'confused': 0, 'heart': 0, 'rocket': 0, 'eyes': 0}, 'timeline_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/14731/timeline', 'performed_via_github_app': None, 'state_reason': None}, 'comment': {'url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/comments/5008087561', 'html_url': 'https://github.com/dolphin-emu/dolphin/pull/14731#issuecomment-5008087561', 'issue_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/14731', 'id': 5008087561, 'node_id': 'IC_kwDOALCn2M8AAAABKoFaCQ', 'user': {'login': 'thethiny', 'id': 6018214, 'node_id': 'MDQ6VXNlcjYwMTgyMTQ=', 'avatar_url': 'https://avatars.githubusercontent.com/u/6018214?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/thethiny', 'html_url': 'https://github.com/thethiny', 'followers_url': 'https://api.github.com/users/thethiny/followers', 'following_url': 'https://api.github.com/users/thethiny/following{/other_user}', 'gists_url': 'https://api.github.com/users/thethiny/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/thethiny/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/thethiny/subscriptions', 'organizations_url': 'https://api.github.com/users/thethiny/orgs', 'repos_url': 'https://api.github.com/users/thethiny/repos', 'events_url': 'https://api.github.com/users/thethiny/events{/privacy}', 'received_events_url': 'https://api.github.com/users/thethiny/received_events', 'type': 'User', 'user_view_type': 'public', 'site_admin': False}, 'created_at': '2026-07-17T22:28:40Z', 'updated_at': '2026-07-17T22:28:56Z', 'body': "> Test Jakers as it has 1 bit of invalid junk beneath valid encryption\r\n\r\nAre we talking about Let's Explore or the Karting game? This is the first time I hear of this game in my life lol.\r\n\r\n> Also, you probably should be using dolphin's existing `MultithreadedCompressor` infrastructure, already used by RVZ and GCZ. Sure, lossless wbfs doesn't do any explicit compression, but removing junk counts as compression and multithreadding would certainly speed it up.\r\n>\r\n> Let me know if you need any help working out how to hook into that infrastructure.\r\n\r\nThanks for offering to help, I pushed my changes before I read this. I will look into it. Meanwhile are you able to confirm my commits based on my explanation above?\r\n\r\n", 'author_association': 'NONE', 'reactions': {'url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/comments/5008087561/reactions', 'total_count': 0, '+1': 0, '-1': 0, 'laugh': 0, 'hooray': 0, 'confused': 0, 'heart': 0, 'rocket': 0, 'eyes': 0}, 'performed_via_github_app': None, 'minimized': None}, 'repository': {'id': 11577304, 'node_id': 'MDEwOlJlcG9zaXRvcnkxMTU3NzMwNA==', 'name': 'dolphin', 'full_name': 'dolphin-emu/dolphin', 'private': False, 'owner': {'login': 'dolphin-emu', 'id': 5050316, 'node_id': 'MDEyOk9yZ2FuaXphdGlvbjUwNTAzMTY=', 'avatar_url': 'https://avatars.githubusercontent.com/u/5050316?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/dolphin-emu', 'html_url': 'https://github.com/dolphin-emu', 'followers_url': 'https://api.github.com/users/dolphin-emu/followers', 'following_url': 'https://api.github.com/users/dolphin-emu/following{/other_user}', 'gists_url': 'https://api.github.com/users/dolphin-emu/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/dolphin-emu/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/dolphin-emu/subscriptions', 'organizations_url': 'https://api.github.com/users/dolphin-emu/orgs', 'repos_url': 'https://api.github.com/users/dolphin-emu/repos', 'events_url': 'https://api.github.com/users/dolphin-emu/events{/privacy}', 'received_events_url': 'https://api.github.com/users/dolphin-emu/received_events', 'type': 'Organization', 'user_view_type': 'public', 'site_admin': False}, 'html_url': 'https://github.com/dolphin-emu/dolphin', 'description': 'Dolphin is a GameCube / Wii emulator, allowing you to play games for these two platforms on PC with improvements.', 'fork': False, 'url': 'https://api.github.com/repos/dolphin-emu/dolphin', 'forks_url': 'https://api.github.com/repos/dolphin-emu/dolphin/forks', 'keys_url': 'https://api.github.com/repos/dolphin-emu/dolphin/keys{/key_id}', 'collaborators_url': 'https://api.github.com/repos/dolphin-emu/dolphin/collaborators{/collaborator}', 'teams_url': 'https://api.github.com/repos/dolphin-emu/dolphin/teams', 'hooks_url': 'https://api.github.com/repos/dolphin-emu/dolphin/hooks', 'issue_events_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/events{/number}', 'events_url': 'https://api.github.com/repos/dolphin-emu/dolphin/events', 'assignees_url': 'https://api.github.com/repos/dolphin-emu/dolphin/assignees{/user}', 'branches_url': 'https://api.github.com/repos/dolphin-emu/dolphin/branches{/branch}', 'tags_url': 'https://api.github.com/repos/dolphin-emu/dolphin/tags', 'blobs_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/blobs{/sha}', 'git_tags_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/tags{/sha}', 'git_refs_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/refs{/sha}', 'trees_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/trees{/sha}', 'statuses_url': 'https://api.github.com/repos/dolphin-emu/dolphin/statuses/{sha}', 'languages_url': 'https://api.github.com/repos/dolphin-emu/dolphin/languages', 'stargazers_url': 'https://api.github.com/repos/dolphin-emu/dolphin/stargazers', 'contributors_url': 'https://api.github.com/repos/dolphin-emu/dolphin/contributors', 'subscribers_url': 'https://api.github.com/repos/dolphin-emu/dolphin/subscribers', 'subscription_url': 'https://api.github.com/repos/dolphin-emu/dolphin/subscription', 'commits_url': 'https://api.github.com/repos/dolphin-emu/dolphin/commits{/sha}', 'git_commits_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/commits{/sha}', 'comments_url': 'https://api.github.com/repos/dolphin-emu/dolphin/comments{/number}', 'issue_comment_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/comments{/number}', 'contents_url': 'https://api.github.com/repos/dolphin-emu/dolphin/contents/{+path}', 'compare_url': 'https://api.github.com/repos/dolphin-emu/dolphin/compare/{base}...{head}', 'merges_url': 'https://api.github.com/repos/dolphin-emu/dolphin/merges', 'archive_url': 'https://api.github.com/repos/dolphin-emu/dolphin/{archive_format}{/ref}', 'downloads_url': 'https://api.github.com/repos/dolphin-emu/dolphin/downloads', 'issues_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues{/number}', 'pulls_url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls{/number}', 'milestones_url': 'https://api.github.com/repos/dolphin-emu/dolphin/milestones{/number}', 'notifications_url': 'https://api.github.com/repos/dolphin-emu/dolphin/notifications{?since,all,participating}', 'labels_url': 'https://api.github.com/repos/dolphin-emu/dolphin/labels{/name}', 'releases_url': 'https://api.github.com/repos/dolphin-emu/dolphin/releases{/id}', 'deployments_url': 'https://api.github.com/repos/dolphin-emu/dolphin/deployments', 'created_at': '2013-07-22T09:07:57Z', 'updated_at': '2026-07-17T13:03:27Z', 'pushed_at': '2026-07-15T20:58:02Z', 'git_url': 'git://github.com/dolphin-emu/dolphin.git', 'ssh_url': 'git@github.com:dolphin-emu/dolphin.git', 'clone_url': 'https://github.com/dolphin-emu/dolphin.git', 'svn_url': 'https://github.com/dolphin-emu/dolphin', 'homepage': 'https://dolphin-emu.org', 'size': 558444, 'stargazers_count': 15268, 'watchers_count': 15268, 'language': 'C++', 'has_issues': False, 'has_projects': False, 'has_downloads': True, 'has_wiki': True, 'has_pages': False, 'has_discussions': False, 'forks_count': 3162, 'mirror_url': None, 'archived': False, 'disabled': False, 'open_issues_count': 447, 'license': {'key': 'other', 'name': 'Other', 'spdx_id': 'NOASSERTION', 'url': None, 'node_id': 'MDc6TGljZW5zZTA='}, 'allow_forking': True, 'is_template': False, 'web_commit_signoff_required': False, 'has_pull_requests': True, 'pull_request_creation_policy': 'all', 'topics': ['cpp', 'emulation', 'emulator', 'gamecube', 'wii'], 'visibility': 'public', 'forks': 3162, 'open_issues': 447, 'watchers': 15268, 'default_branch': 'master', 'custom_properties': {}}, 'organization': {'login': 'dolphin-emu', 'id': 5050316, 'node_id': 'MDEyOk9yZ2FuaXphdGlvbjUwNTAzMTY=', 'url': 'https://api.github.com/orgs/dolphin-emu', 'repos_url': 'https://api.github.com/orgs/dolphin-emu/repos', 'events_url': 'https://api.github.com/orgs/dolphin-emu/events', 'hooks_url': 'https://api.github.com/orgs/dolphin-emu/hooks', 'issues_url': 'https://api.github.com/orgs/dolphin-emu/issues', 'members_url': 'https://api.github.com/orgs/dolphin-emu/members{/member}', 'public_members_url': 'https://api.github.com/orgs/dolphin-emu/public_members{/member}', 'avatar_url': 'https://avatars.githubusercontent.com/u/5050316?v=4', 'description': ''}, 'sender': {'login': 'thethiny', 'id': 6018214, 'node_id': 'MDQ6VXNlcjYwMTgyMTQ=', 'avatar_url': 'https://avatars.githubusercontent.com/u/6018214?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/thethiny', 'html_url': 'https://github.com/thethiny', 'followers_url': 'https://api.github.com/users/thethiny/followers', 'following_url': 'https://api.github.com/users/thethiny/following{/other_user}', 'gists_url': 'https://api.github.com/users/thethiny/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/thethiny/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/thethiny/subscriptions', 'organizations_url': 'https://api.github.com/users/thethiny/orgs', 'repos_url': 'https://api.github.com/users/thethiny/repos', 'events_url': 'https://api.github.com/users/thethiny/events{/privacy}', 'received_events_url': 'https://api.github.com/users/thethiny/received_events', 'type': 'User', 'user_view_type': 'public', 'site_admin': False}, 'installation': {'id': 35437981, 'node_id': 'MDIzOkludGVncmF0aW9uSW5zdGFsbGF0aW9uMzU0Mzc5ODE='}}, 'type': 'gh_issue_comment'}
2026-07-17T22:28:42.459899	{'source': 'ghhookparser', 'repo': 'dolphin-emu/dolphin', 'author': 'thethiny', 'action': 'created', 'id': 14731, 'title': 'Convert To WBFS Support', 'url': 'https://github.com/dolphin-emu/dolphin/pull/14731#issuecomment-5008087561', 'safe_author': False, 'body': "> Test Jakers as it has 1 bit of invalid junk beneath valid encryption\r\n\r\nAre we talking about Let's Explore or the Karting game? This is the first time I hear of this game in my life lol.\r\n\r\n> Also, you probably should be using dolphin's existing `MultithreadedCompressor` infrastructure, already used by RVZ and GCZ. Sure, lossless wbfs doesn't do any explicit compression, but removing junk counts as compression and multithreadding would certainly speed it up.\r\n> \r\n> Let me know if you need any help working out how to hook into that infrastructure.\r\nThanks for offering to help, I pushed my changes before I read this. I will look into it. Meanwhile are you able to confirm my commits based on my explanation above?\r\n\r\n", 'raw': {'action': 'created', 'issue': {'url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/14731', 'repository_url': 'https://api.github.com/repos/dolphin-emu/dolphin', 'labels_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/14731/labels{/name}', 'comments_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/14731/comments', 'events_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/14731/events', 'html_url': 'https://github.com/dolphin-emu/dolphin/pull/14731', 'id': 4888393904, 'node_id': 'PR_kwDOALCn2M7x0I-2', 'number': 14731, 'title': 'Convert To WBFS Support', 'user': {'login': 'thethiny', 'id': 6018214, 'node_id': 'MDQ6VXNlcjYwMTgyMTQ=', 'avatar_url': 'https://avatars.githubusercontent.com/u/6018214?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/thethiny', 'html_url': 'https://github.com/thethiny', 'followers_url': 'https://api.github.com/users/thethiny/followers', 'following_url': 'https://api.github.com/users/thethiny/following{/other_user}', 'gists_url': 'https://api.github.com/users/thethiny/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/thethiny/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/thethiny/subscriptions', 'organizations_url': 'https://api.github.com/users/thethiny/orgs', 'repos_url': 'https://api.github.com/users/thethiny/repos', 'events_url': 'https://api.github.com/users/thethiny/events{/privacy}', 'received_events_url': 'https://api.github.com/users/thethiny/received_events', 'type': 'User', 'user_view_type': 'public', 'site_admin': False}, 'labels': [], 'state': 'open', 'locked': False, 'assignees': [], 'milestone': None, 'comments': 36, 'created_at': '2026-07-15T01:16:25Z', 'updated_at': '2026-07-17T22:28:40Z', 'closed_at': None, 'assignee': None, 'author_association': 'NONE', 'issue_field_values': [], 'type': None, 'active_lock_reason': None, 'draft': False, 'pull_request': {'url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/14731', 'html_url': 'https://github.com/dolphin-emu/dolphin/pull/14731', 'diff_url': 'https://github.com/dolphin-emu/dolphin/pull/14731.diff', 'patch_url': 'https://github.com/dolphin-emu/dolphin/pull/14731.patch', 'merged_at': None}, 'body': "This PR introduces Conversion **to** WBFS support. WBFS is the format that is used by USB Loaders on a real Wii device.\r\n\r\n## Design decisions & hardcoded values\r\nThe writer uses fixed sector sizes that match what [libwbfs (the reference implementation by kwiirk)](https://github.com/kwiirk/wbfs/blob/master/libwbfs/libwbfs.c#L128-L134) computes for a standard single-layer Wii disc. These 2 hardcodes are stable and work correctly across all my testings.\r\n- HD sector shift: 9 (512 bytes)\r\n- WBFS sector shift: 21 (2 MiB)\r\nThese are not configurable via the UI. All existing WBFS tools use these values, and since the aim is to support USB Loaders then this has been tested and it is working on a real Wii.\r\n\r\nConverting from WBFS is not enabled. The existing `WbfsFileReader` reports `DataSizeType::UpperBound`, and `ShouldAllowConversion()` requires `Accurate`. I am able to support this but since it was hardcoded by the Dolphin team I thought a discussion is warranted.\r\n\r\n## Testing\r\n- Verified with DolphinTool header and DolphinTool verify\r\n- Verified with wit FILETYPE and wit DUMP (Wiimm's ISO Tools recognizes valid WBFS structure, partitions, encryption)\r\n- Tested ISO to WBFS and RVZ to WBFS conversions\r\n- Output file sizes match Wii Backup Manager when scrubbing is enabled (~0.1% difference), works when scrubbing is disabled.\r\n- Output WBFS files play correctly in Dolphin\r\n- Output WBFS files play correctly on a real Wii using USB Loader GX e25c4f3\r\n", 'reactions': {'url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/14731/reactions', 'total_count': 2, '+1': 2, '-1': 0, 'laugh': 0, 'hooray': 0, 'confused': 0, 'heart': 0, 'rocket': 0, 'eyes': 0}, 'timeline_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/14731/timeline', 'performed_via_github_app': None, 'state_reason': None}, 'comment': {'url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/comments/5008087561', 'html_url': 'https://github.com/dolphin-emu/dolphin/pull/14731#issuecomment-5008087561', 'issue_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/14731', 'id': 5008087561, 'node_id': 'IC_kwDOALCn2M8AAAABKoFaCQ', 'user': {'login': 'thethiny', 'id': 6018214, 'node_id': 'MDQ6VXNlcjYwMTgyMTQ=', 'avatar_url': 'https://avatars.githubusercontent.com/u/6018214?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/thethiny', 'html_url': 'https://github.com/thethiny', 'followers_url': 'https://api.github.com/users/thethiny/followers', 'following_url': 'https://api.github.com/users/thethiny/following{/other_user}', 'gists_url': 'https://api.github.com/users/thethiny/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/thethiny/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/thethiny/subscriptions', 'organizations_url': 'https://api.github.com/users/thethiny/orgs', 'repos_url': 'https://api.github.com/users/thethiny/repos', 'events_url': 'https://api.github.com/users/thethiny/events{/privacy}', 'received_events_url': 'https://api.github.com/users/thethiny/received_events', 'type': 'User', 'user_view_type': 'public', 'site_admin': False}, 'created_at': '2026-07-17T22:28:40Z', 'updated_at': '2026-07-17T22:28:40Z', 'body': "> Test Jakers as it has 1 bit of invalid junk beneath valid encryption\r\n\r\nAre we talking about Let's Explore or the Karting game? This is the first time I hear of this game in my life lol.\r\n\r\n> Also, you probably should be using dolphin's existing `MultithreadedCompressor` infrastructure, already used by RVZ and GCZ. Sure, lossless wbfs doesn't do any explicit compression, but removing junk counts as compression and multithreadding would certainly speed it up.\r\n> \r\n> Let me know if you need any help working out how to hook into that infrastructure.\r\nThanks for offering to help, I pushed my changes before I read this. I will look into it. Meanwhile are you able to confirm my commits based on my explanation above?\r\n\r\n", 'author_association': 'NONE', 'reactions': {'url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/comments/5008087561/reactions', 'total_count': 0, '+1': 0, '-1': 0, 'laugh': 0, 'hooray': 0, 'confused': 0, 'heart': 0, 'rocket': 0, 'eyes': 0}, 'performed_via_github_app': None, 'minimized': None}, 'repository': {'id': 11577304, 'node_id': 'MDEwOlJlcG9zaXRvcnkxMTU3NzMwNA==', 'name': 'dolphin', 'full_name': 'dolphin-emu/dolphin', 'private': False, 'owner': {'login': 'dolphin-emu', 'id': 5050316, 'node_id': 'MDEyOk9yZ2FuaXphdGlvbjUwNTAzMTY=', 'avatar_url': 'https://avatars.githubusercontent.com/u/5050316?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/dolphin-emu', 'html_url': 'https://github.com/dolphin-emu', 'followers_url': 'https://api.github.com/users/dolphin-emu/followers', 'following_url': 'https://api.github.com/users/dolphin-emu/following{/other_user}', 'gists_url': 'https://api.github.com/users/dolphin-emu/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/dolphin-emu/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/dolphin-emu/subscriptions', 'organizations_url': 'https://api.github.com/users/dolphin-emu/orgs', 'repos_url': 'https://api.github.com/users/dolphin-emu/repos', 'events_url': 'https://api.github.com/users/dolphin-emu/events{/privacy}', 'received_events_url': 'https://api.github.com/users/dolphin-emu/received_events', 'type': 'Organization', 'user_view_type': 'public', 'site_admin': False}, 'html_url': 'https://github.com/dolphin-emu/dolphin', 'description': 'Dolphin is a GameCube / Wii emulator, allowing you to play games for these two platforms on PC with improvements.', 'fork': False, 'url': 'https://api.github.com/repos/dolphin-emu/dolphin', 'forks_url': 'https://api.github.com/repos/dolphin-emu/dolphin/forks', 'keys_url': 'https://api.github.com/repos/dolphin-emu/dolphin/keys{/key_id}', 'collaborators_url': 'https://api.github.com/repos/dolphin-emu/dolphin/collaborators{/collaborator}', 'teams_url': 'https://api.github.com/repos/dolphin-emu/dolphin/teams', 'hooks_url': 'https://api.github.com/repos/dolphin-emu/dolphin/hooks', 'issue_events_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/events{/number}', 'events_url': 'https://api.github.com/repos/dolphin-emu/dolphin/events', 'assignees_url': 'https://api.github.com/repos/dolphin-emu/dolphin/assignees{/user}', 'branches_url': 'https://api.github.com/repos/dolphin-emu/dolphin/branches{/branch}', 'tags_url': 'https://api.github.com/repos/dolphin-emu/dolphin/tags', 'blobs_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/blobs{/sha}', 'git_tags_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/tags{/sha}', 'git_refs_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/refs{/sha}', 'trees_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/trees{/sha}', 'statuses_url': 'https://api.github.com/repos/dolphin-emu/dolphin/statuses/{sha}', 'languages_url': 'https://api.github.com/repos/dolphin-emu/dolphin/languages', 'stargazers_url': 'https://api.github.com/repos/dolphin-emu/dolphin/stargazers', 'contributors_url': 'https://api.github.com/repos/dolphin-emu/dolphin/contributors', 'subscribers_url': 'https://api.github.com/repos/dolphin-emu/dolphin/subscribers', 'subscription_url': 'https://api.github.com/repos/dolphin-emu/dolphin/subscription', 'commits_url': 'https://api.github.com/repos/dolphin-emu/dolphin/commits{/sha}', 'git_commits_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/commits{/sha}', 'comments_url': 'https://api.github.com/repos/dolphin-emu/dolphin/comments{/number}', 'issue_comment_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/comments{/number}', 'contents_url': 'https://api.github.com/repos/dolphin-emu/dolphin/contents/{+path}', 'compare_url': 'https://api.github.com/repos/dolphin-emu/dolphin/compare/{base}...{head}', 'merges_url': 'https://api.github.com/repos/dolphin-emu/dolphin/merges', 'archive_url': 'https://api.github.com/repos/dolphin-emu/dolphin/{archive_format}{/ref}', 'downloads_url': 'https://api.github.com/repos/dolphin-emu/dolphin/downloads', 'issues_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues{/number}', 'pulls_url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls{/number}', 'milestones_url': 'https://api.github.com/repos/dolphin-emu/dolphin/milestones{/number}', 'notifications_url': 'https://api.github.com/repos/dolphin-emu/dolphin/notifications{?since,all,participating}', 'labels_url': 'https://api.github.com/repos/dolphin-emu/dolphin/labels{/name}', 'releases_url': 'https://api.github.com/repos/dolphin-emu/dolphin/releases{/id}', 'deployments_url': 'https://api.github.com/repos/dolphin-emu/dolphin/deployments', 'created_at': '2013-07-22T09:07:57Z', 'updated_at': '2026-07-17T13:03:27Z', 'pushed_at': '2026-07-15T20:58:02Z', 'git_url': 'git://github.com/dolphin-emu/dolphin.git', 'ssh_url': 'git@github.com:dolphin-emu/dolphin.git', 'clone_url': 'https://github.com/dolphin-emu/dolphin.git', 'svn_url': 'https://github.com/dolphin-emu/dolphin', 'homepage': 'https://dolphin-emu.org', 'size': 558444, 'stargazers_count': 15268, 'watchers_count': 15268, 'language': 'C++', 'has_issues': False, 'has_projects': False, 'has_downloads': True, 'has_wiki': True, 'has_pages': False, 'has_discussions': False, 'forks_count': 3162, 'mirror_url': None, 'archived': False, 'disabled': False, 'open_issues_count': 447, 'license': {'key': 'other', 'name': 'Other', 'spdx_id': 'NOASSERTION', 'url': None, 'node_id': 'MDc6TGljZW5zZTA='}, 'allow_forking': True, 'is_template': False, 'web_commit_signoff_required': False, 'has_pull_requests': True, 'pull_request_creation_policy': 'all', 'topics': ['cpp', 'emulation', 'emulator', 'gamecube', 'wii'], 'visibility': 'public', 'forks': 3162, 'open_issues': 447, 'watchers': 15268, 'default_branch': 'master', 'custom_properties': {}}, 'organization': {'login': 'dolphin-emu', 'id': 5050316, 'node_id': 'MDEyOk9yZ2FuaXphdGlvbjUwNTAzMTY=', 'url': 'https://api.github.com/orgs/dolphin-emu', 'repos_url': 'https://api.github.com/orgs/dolphin-emu/repos', 'events_url': 'https://api.github.com/orgs/dolphin-emu/events', 'hooks_url': 'https://api.github.com/orgs/dolphin-emu/hooks', 'issues_url': 'https://api.github.com/orgs/dolphin-emu/issues', 'members_url': 'https://api.github.com/orgs/dolphin-emu/members{/member}', 'public_members_url': 'https://api.github.com/orgs/dolphin-emu/public_members{/member}', 'avatar_url': 'https://avatars.githubusercontent.com/u/5050316?v=4', 'description': ''}, 'sender': {'login': 'thethiny', 'id': 6018214, 'node_id': 'MDQ6VXNlcjYwMTgyMTQ=', 'avatar_url': 'https://avatars.githubusercontent.com/u/6018214?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/thethiny', 'html_url': 'https://github.com/thethiny', 'followers_url': 'https://api.github.com/users/thethiny/followers', 'following_url': 'https://api.github.com/users/thethiny/following{/other_user}', 'gists_url': 'https://api.github.com/users/thethiny/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/thethiny/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/thethiny/subscriptions', 'organizations_url': 'https://api.github.com/users/thethiny/orgs', 'repos_url': 'https://api.github.com/users/thethiny/repos', 'events_url': 'https://api.github.com/users/thethiny/events{/privacy}', 'received_events_url': 'https://api.github.com/users/thethiny/received_events', 'type': 'User', 'user_view_type': 'public', 'site_admin': False}, 'installation': {'id': 35437981, 'node_id': 'MDIzOkludGVncmF0aW9uSW5zdGFsbGF0aW9uMzU0Mzc5ODE='}}, 'type': 'gh_issue_comment'}
2026-07-17T22:27:21.225648	{'source': 'ghhookparser', 'repo': 'dolphin-emu/dolphin', 'author': 'thethiny', 'action': 'created', 'id': 14731, 'title': 'Convert To WBFS Support', 'url': 'https://github.com/dolphin-emu/dolphin/pull/14731#issuecomment-5008077250', 'safe_author': False, 'body': "> You should expect a noticeable difference due to lossless having to check all the junk to be valid. Lossy can just read the fst and skip the gaps.\r\n\r\nI did indeed notice that, and the slowdown is significant on small games but not that much on big games. But the biggest slowdown came from the refactor rather than the Lossless conversion.\r\n\r\n\r\nHere is my table:\r\n\r\n## Benchmarks\r\n\r\nSource: `F:\\` (7200 RPM HDD), Output: `D:\\` (5400 RPM HDD). Each test run 3 times, averaged.\r\n\r\n### Rhythm Heaven Fever (USA) ISO -> WBFS\r\n\r\n| Commit     | Message                                   | Scrub | Avg Time | Size          | SHA1       |\r\n| ---------- | ----------------------------------------- | ----- | -------- | ------------- | ---------- |\r\n| `35b4f78b` | Lossy WBFS no scrubbing                   | off   | ~1m      | 4,645,191,680 | `7b7b66ed` |\r\n| `35b4f78b` | Lossy WBFS with scrubbing                 | on    | 1.4s     | 662,700,032   | `2e12c0b3` |\r\n| `8b5134c1` | Lossless WBFS NKITv2 maintain partitions  | off   | 3.8s     | 662,700,032   | `3584deca` |\r\n| `8b5134c1` | Lossless WBFS NKITv2 scrub U/C partitions | on    | 3.7s     | 465,567,744   | `e9054dc1` |\r\n| `9ebb2a79` | Utilize dolphin's existing methods        | N/A   | 10.3s    | 662,700,032   | `ba4d0e44` |\r\n| `81f33697` | Support encrypted partitions              | N/A   | 11.4s    | 662,700,032   | `ba4d0e44` |\r\n\r\n### Mario Kart Wii (USA) ISO -> WBFS\r\n\r\n| Commit     | Message                                   | Scrub | Avg Time | Size          | SHA1       |\r\n| ---------- | ----------------------------------------- | ----- | -------- | ------------- | ---------- |\r\n| `35b4f78b` | Lossy WBFS no scrubbing                   | off   | ~27s     | 4,624,220,160 | `b00eb94b` |\r\n| `35b4f78b` | Lossy WBFS with scrubbing                 | on    | ~15s     | 2,984,247,296 | `aadefdde` |\r\n| `8b5134c1` | Lossless WBFS NKITv2 maintain partitions  | off   | ~19s     | 2,984,247,296 | `6b11fbe3` |\r\n| `8b5134c1` | Lossless WBFS NKITv2 scrub U/C partitions | on    | ~16s     | 2,780,823,552 | `6f844ea5` |\r\n| `9ebb2a79` | Utilize dolphin's existing methods        | N/A   | ~25s     | 2,984,247,296 | `f16fced4` |\r\n| `81f33697` | Support encrypted partitions              | N/A   | ~26s     | 2,984,247,296 | `f16fced4` |\r\n\r\nScrubbing U/C partitions seems to save around 200MB regardless of game size, which is very negligible compared to the benefits of preservation.\r\n\r\nMoving from WBFS specific functions to generic `CreateDisc`, `Volume`, and title parsers seems to introduce a consistent ~6 second slowdown, which tells me the overhead is from the Volume init rather then block processing.\r\nIntroducing the `ReadPartitionInfo` and `CreateDisc` in the 4th commit seems to introduce around 1 second of slowdown which IMHO is acceptable for a proper full roundtrip preservation.\r\n\r\n### Super Smash Bros. Brawl (USA) ISO -> WBFS (Commit2 vs Commit3 only)\r\n\r\n| Commit     | Message                                  | Scrub | Avg Time | Delta from C2 |\r\n| ---------- | ---------------------------------------- | ----- | -------- | ------------- |\r\n| `8b5134c1` | Lossless WBFS NKITv2 maintain partitions | off   | ~1m02s   | -             |\r\n| `9ebb2a79` | Utilize dolphin's existing methods       | N/A   | ~1m10s   | +8s           |\r\n\r\n## CreateDisc/Volume overhead across games\r\n\r\n| Game  | Disc Size   | Partitions | C2 Avg | C3 Avg | Delta |\r\n| ----- | ----------- | ---------- | ------ | ------ | ----- |\r\n| RHF   | 4.7 GB (SL) | 2          | 3.8s   | 10.3s  | +6.5s |\r\n| MKWii | 4.7 GB (SL) | 3          | ~19s   | ~25s   | +6s   |\r\n| SSBB  | 8.5 GB (DL) | 14         | ~1m02s | ~1m10s | +8s   |\r\n\r\n\r\n## Completed and remaining tasks\r\n### Done\r\nRemove hardcoded common key, use `CreateDisc` - Done. `Volume::GetTicket().GetTitleKey()` handles all key variants.\r\nUnconditional junk reconstruction in `Read()` - Done. Always reconstructs, no flag as discussed.\r\nAdd `MD5` + `XXHash64` - Done. All four hashes in NKit header (flags=0x001F). I tested without them and the speed difference was so tiny.\r\nDrop scrub mode - Done. Lossless only with no scrub on the GUI.\r\nPartition-level encrypted reconstruction - Done. WiiEncryptionCache + ReadWiiDecrypted.\r\n### Not yet\r\nMake RVZPack generic -  Not extracted into a shared utility. WBFS and RVZ both use LaggedFibonacciGenerator but have separate scan loops. Should I proceed with this, or will it be out of scope for this PR since it's WBFS only?\r\nWBFS -> RVZ with soft warning for lossy - Investigating this and will most likely implement.\r\nDual-layer .wbfs+.wbf1 split - Will investigate, since USB Loaders on FAT-based systems require the split, NTFS does not, and incorporating it requires a GUI update.\r\n\r\n## Open Questions\r\n\r\n**Reuse Dolphin's disc verification code?**\r\nWe compute hashes directly instead of going through VolumeVerifier. My testing shows 0 performance impact. Shall we still consider this?\r\n\r\n**FST-walk writer optimization?**\r\nI tried using `FileSystem::FindFileInfo()` (same approach as RVZPack) to skip AES decryption for blocks with file data. Two implementations were tested:\r\n\r\n1. Per-sector `FindFileInfo()` during scan - 573K heap-allocating map lookups, 2-3x slowdown\r\n2. Precomputed bitmap via recursive FST walk - no measurable speedup\r\n\r\nNKit v2 requires SHA-1/CRC32/MD5/XXHash64 over the full original disc, so every byte must be read and hashed regardless. The I/O dominates - disabling MD5 and XXHash64 showed zero performance difference, confirming CPU-side work (hashing, decryption) is not the bottleneck. The FST walk added overhead without measurable speedup, since AES decryption is hardware-accelerated and already negligible.\r\n\r\nFor reference, WBFS Manager achieves 0.18s because it produces traditional WBFS without NKit hashes and only reads sectors with file data (~442MB). This speed is unachievable while maintaining NKit v2 verification as confirmed by @Nanook.\r\n\r\nI've reverted this optimization for now. Should we revisit it, or is the current approach acceptable?\r\n", 'raw': {'action': 'created', 'issue': {'url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/14731', 'repository_url': 'https://api.github.com/repos/dolphin-emu/dolphin', 'labels_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/14731/labels{/name}', 'comments_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/14731/comments', 'events_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/14731/events', 'html_url': 'https://github.com/dolphin-emu/dolphin/pull/14731', 'id': 4888393904, 'node_id': 'PR_kwDOALCn2M7x0I-2', 'number': 14731, 'title': 'Convert To WBFS Support', 'user': {'login': 'thethiny', 'id': 6018214, 'node_id': 'MDQ6VXNlcjYwMTgyMTQ=', 'avatar_url': 'https://avatars.githubusercontent.com/u/6018214?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/thethiny', 'html_url': 'https://github.com/thethiny', 'followers_url': 'https://api.github.com/users/thethiny/followers', 'following_url': 'https://api.github.com/users/thethiny/following{/other_user}', 'gists_url': 'https://api.github.com/users/thethiny/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/thethiny/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/thethiny/subscriptions', 'organizations_url': 'https://api.github.com/users/thethiny/orgs', 'repos_url': 'https://api.github.com/users/thethiny/repos', 'events_url': 'https://api.github.com/users/thethiny/events{/privacy}', 'received_events_url': 'https://api.github.com/users/thethiny/received_events', 'type': 'User', 'user_view_type': 'public', 'site_admin': False}, 'labels': [], 'state': 'open', 'locked': False, 'assignees': [], 'milestone': None, 'comments': 35, 'created_at': '2026-07-15T01:16:25Z', 'updated_at': '2026-07-17T22:27:19Z', 'closed_at': None, 'assignee': None, 'author_association': 'NONE', 'issue_field_values': [], 'type': None, 'active_lock_reason': None, 'draft': False, 'pull_request': {'url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/14731', 'html_url': 'https://github.com/dolphin-emu/dolphin/pull/14731', 'diff_url': 'https://github.com/dolphin-emu/dolphin/pull/14731.diff', 'patch_url': 'https://github.com/dolphin-emu/dolphin/pull/14731.patch', 'merged_at': None}, 'body': "This PR introduces Conversion **to** WBFS support. WBFS is the format that is used by USB Loaders on a real Wii device.\r\n\r\n## Design decisions & hardcoded values\r\nThe writer uses fixed sector sizes that match what [libwbfs (the reference implementation by kwiirk)](https://github.com/kwiirk/wbfs/blob/master/libwbfs/libwbfs.c#L128-L134) computes for a standard single-layer Wii disc. These 2 hardcodes are stable and work correctly across all my testings.\r\n- HD sector shift: 9 (512 bytes)\r\n- WBFS sector shift: 21 (2 MiB)\r\nThese are not configurable via the UI. All existing WBFS tools use these values, and since the aim is to support USB Loaders then this has been tested and it is working on a real Wii.\r\n\r\nConverting from WBFS is not enabled. The existing `WbfsFileReader` reports `DataSizeType::UpperBound`, and `ShouldAllowConversion()` requires `Accurate`. I am able to support this but since it was hardcoded by the Dolphin team I thought a discussion is warranted.\r\n\r\n## Testing\r\n- Verified with DolphinTool header and DolphinTool verify\r\n- Verified with wit FILETYPE and wit DUMP (Wiimm's ISO Tools recognizes valid WBFS structure, partitions, encryption)\r\n- Tested ISO to WBFS and RVZ to WBFS conversions\r\n- Output file sizes match Wii Backup Manager when scrubbing is enabled (~0.1% difference), works when scrubbing is disabled.\r\n- Output WBFS files play correctly in Dolphin\r\n- Output WBFS files play correctly on a real Wii using USB Loader GX e25c4f3\r\n", 'reactions': {'url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/14731/reactions', 'total_count': 2, '+1': 2, '-1': 0, 'laugh': 0, 'hooray': 0, 'confused': 0, 'heart': 0, 'rocket': 0, 'eyes': 0}, 'timeline_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/14731/timeline', 'performed_via_github_app': None, 'state_reason': None}, 'comment': {'url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/comments/5008077250', 'html_url': 'https://github.com/dolphin-emu/dolphin/pull/14731#issuecomment-5008077250', 'issue_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/14731', 'id': 5008077250, 'node_id': 'IC_kwDOALCn2M8AAAABKoExwg', 'user': {'login': 'thethiny', 'id': 6018214, 'node_id': 'MDQ6VXNlcjYwMTgyMTQ=', 'avatar_url': 'https://avatars.githubusercontent.com/u/6018214?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/thethiny', 'html_url': 'https://github.com/thethiny', 'followers_url': 'https://api.github.com/users/thethiny/followers', 'following_url': 'https://api.github.com/users/thethiny/following{/other_user}', 'gists_url': 'https://api.github.com/users/thethiny/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/thethiny/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/thethiny/subscriptions', 'organizations_url': 'https://api.github.com/users/thethiny/orgs', 'repos_url': 'https://api.github.com/users/thethiny/repos', 'events_url': 'https://api.github.com/users/thethiny/events{/privacy}', 'received_events_url': 'https://api.github.com/users/thethiny/received_events', 'type': 'User', 'user_view_type': 'public', 'site_admin': False}, 'created_at': '2026-07-17T22:27:19Z', 'updated_at': '2026-07-17T22:27:19Z', 'body': "> You should expect a noticeable difference due to lossless having to check all the junk to be valid. Lossy can just read the fst and skip the gaps.\r\n\r\nI did indeed notice that, and the slowdown is significant on small games but not that much on big games. But the biggest slowdown came from the refactor rather than the Lossless conversion.\r\n\r\n\r\nHere is my table:\r\n\r\n## Benchmarks\r\n\r\nSource: `F:\\` (7200 RPM HDD), Output: `D:\\` (5400 RPM HDD). Each test run 3 times, averaged.\r\n\r\n### Rhythm Heaven Fever (USA) ISO -> WBFS\r\n\r\n| Commit     | Message                                   | Scrub | Avg Time | Size          | SHA1       |\r\n| ---------- | ----------------------------------------- | ----- | -------- | ------------- | ---------- |\r\n| `35b4f78b` | Lossy WBFS no scrubbing                   | off   | ~1m      | 4,645,191,680 | `7b7b66ed` |\r\n| `35b4f78b` | Lossy WBFS with scrubbing                 | on    | 1.4s     | 662,700,032   | `2e12c0b3` |\r\n| `8b5134c1` | Lossless WBFS NKITv2 maintain partitions  | off   | 3.8s     | 662,700,032   | `3584deca` |\r\n| `8b5134c1` | Lossless WBFS NKITv2 scrub U/C partitions | on    | 3.7s     | 465,567,744   | `e9054dc1` |\r\n| `9ebb2a79` | Utilize dolphin's existing methods        | N/A   | 10.3s    | 662,700,032   | `ba4d0e44` |\r\n| `81f33697` | Support encrypted partitions              | N/A   | 11.4s    | 662,700,032   | `ba4d0e44` |\r\n\r\n### Mario Kart Wii (USA) ISO -> WBFS\r\n\r\n| Commit     | Message                                   | Scrub | Avg Time | Size          | SHA1       |\r\n| ---------- | ----------------------------------------- | ----- | -------- | ------------- | ---------- |\r\n| `35b4f78b` | Lossy WBFS no scrubbing                   | off   | ~27s     | 4,624,220,160 | `b00eb94b` |\r\n| `35b4f78b` | Lossy WBFS with scrubbing                 | on    | ~15s     | 2,984,247,296 | `aadefdde` |\r\n| `8b5134c1` | Lossless WBFS NKITv2 maintain partitions  | off   | ~19s     | 2,984,247,296 | `6b11fbe3` |\r\n| `8b5134c1` | Lossless WBFS NKITv2 scrub U/C partitions | on    | ~16s     | 2,780,823,552 | `6f844ea5` |\r\n| `9ebb2a79` | Utilize dolphin's existing methods        | N/A   | ~25s     | 2,984,247,296 | `f16fced4` |\r\n| `81f33697` | Support encrypted partitions              | N/A   | ~26s     | 2,984,247,296 | `f16fced4` |\r\n\r\nScrubbing U/C partitions seems to save around 200MB regardless of game size, which is very negligible compared to the benefits of preservation.\r\n\r\nMoving from WBFS specific functions to generic `CreateDisc`, `Volume`, and title parsers seems to introduce a consistent ~6 second slowdown, which tells me the overhead is from the Volume init rather then block processing.\r\nIntroducing the `ReadPartitionInfo` and `CreateDisc` in the 4th commit seems to introduce around 1 second of slowdown which IMHO is acceptable for a proper full roundtrip preservation.\r\n\r\n### Super Smash Bros. Brawl (USA) ISO -> WBFS (Commit2 vs Commit3 only)\r\n\r\n| Commit     | Message                                  | Scrub | Avg Time | Delta from C2 |\r\n| ---------- | ---------------------------------------- | ----- | -------- | ------------- |\r\n| `8b5134c1` | Lossless WBFS NKITv2 maintain partitions | off   | ~1m02s   | -             |\r\n| `9ebb2a79` | Utilize dolphin's existing methods       | N/A   | ~1m10s   | +8s           |\r\n\r\n## CreateDisc/Volume overhead across games\r\n\r\n| Game  | Disc Size   | Partitions | C2 Avg | C3 Avg | Delta |\r\n| ----- | ----------- | ---------- | ------ | ------ | ----- |\r\n| RHF   | 4.7 GB (SL) | 2          | 3.8s   | 10.3s  | +6.5s |\r\n| MKWii | 4.7 GB (SL) | 3          | ~19s   | ~25s   | +6s   |\r\n| SSBB  | 8.5 GB (DL) | 14         | ~1m02s | ~1m10s | +8s   |\r\n\r\n\r\n## Completed and remaining tasks\r\n### Done\r\nRemove hardcoded common key, use `CreateDisc` - Done. `Volume::GetTicket().GetTitleKey()` handles all key variants.\r\nUnconditional junk reconstruction in `Read()` - Done. Always reconstructs, no flag as discussed.\r\nAdd `MD5` + `XXHash64` - Done. All four hashes in NKit header (flags=0x001F). I tested without them and the speed difference was so tiny.\r\nDrop scrub mode - Done. Lossless only with no scrub on the GUI.\r\nPartition-level encrypted reconstruction - Done. WiiEncryptionCache + ReadWiiDecrypted.\r\n### Not yet\r\nMake RVZPack generic -  Not extracted into a shared utility. WBFS and RVZ both use LaggedFibonacciGenerator but have separate scan loops. Should I proceed with this, or will it be out of scope for this PR since it's WBFS only?\r\nWBFS -> RVZ with soft warning for lossy - Investigating this and will most likely implement.\r\nDual-layer .wbfs+.wbf1 split - Will investigate, since USB Loaders on FAT-based systems require the split, NTFS does not, and incorporating it requires a GUI update.\r\n\r\n## Open Questions\r\n\r\n**Reuse Dolphin's disc verification code?**\r\nWe compute hashes directly instead of going through VolumeVerifier. My testing shows 0 performance impact. Shall we still consider this?\r\n\r\n**FST-walk writer optimization?**\r\nI tried using `FileSystem::FindFileInfo()` (same approach as RVZPack) to skip AES decryption for blocks with file data. Two implementations were tested:\r\n\r\n1. Per-sector `FindFileInfo()` during scan - 573K heap-allocating map lookups, 2-3x slowdown\r\n2. Precomputed bitmap via recursive FST walk - no measurable speedup\r\n\r\nNKit v2 requires SHA-1/CRC32/MD5/XXHash64 over the full original disc, so every byte must be read and hashed regardless. The I/O dominates - disabling MD5 and XXHash64 showed zero performance difference, confirming CPU-side work (hashing, decryption) is not the bottleneck. The FST walk added overhead without measurable speedup, since AES decryption is hardware-accelerated and already negligible.\r\n\r\nFor reference, WBFS Manager achieves 0.18s because it produces traditional WBFS without NKit hashes and only reads sectors with file data (~442MB). This speed is unachievable while maintaining NKit v2 verification as confirmed by @Nanook.\r\n\r\nI've reverted this optimization for now. Should we revisit it, or is the current approach acceptable?\r\n", 'author_association': 'NONE', 'reactions': {'url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/comments/5008077250/reactions', 'total_count': 0, '+1': 0, '-1': 0, 'laugh': 0, 'hooray': 0, 'confused': 0, 'heart': 0, 'rocket': 0, 'eyes': 0}, 'performed_via_github_app': None, 'minimized': None}, 'repository': {'id': 11577304, 'node_id': 'MDEwOlJlcG9zaXRvcnkxMTU3NzMwNA==', 'name': 'dolphin', 'full_name': 'dolphin-emu/dolphin', 'private': False, 'owner': {'login': 'dolphin-emu', 'id': 5050316, 'node_id': 'MDEyOk9yZ2FuaXphdGlvbjUwNTAzMTY=', 'avatar_url': 'https://avatars.githubusercontent.com/u/5050316?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/dolphin-emu', 'html_url': 'https://github.com/dolphin-emu', 'followers_url': 'https://api.github.com/users/dolphin-emu/followers', 'following_url': 'https://api.github.com/users/dolphin-emu/following{/other_user}', 'gists_url': 'https://api.github.com/users/dolphin-emu/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/dolphin-emu/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/dolphin-emu/subscriptions', 'organizations_url': 'https://api.github.com/users/dolphin-emu/orgs', 'repos_url': 'https://api.github.com/users/dolphin-emu/repos', 'events_url': 'https://api.github.com/users/dolphin-emu/events{/privacy}', 'received_events_url': 'https://api.github.com/users/dolphin-emu/received_events', 'type': 'Organization', 'user_view_type': 'public', 'site_admin': False}, 'html_url': 'https://github.com/dolphin-emu/dolphin', 'description': 'Dolphin is a GameCube / Wii emulator, allowing you to play games for these two platforms on PC with improvements.', 'fork': False, 'url': 'https://api.github.com/repos/dolphin-emu/dolphin', 'forks_url': 'https://api.github.com/repos/dolphin-emu/dolphin/forks', 'keys_url': 'https://api.github.com/repos/dolphin-emu/dolphin/keys{/key_id}', 'collaborators_url': 'https://api.github.com/repos/dolphin-emu/dolphin/collaborators{/collaborator}', 'teams_url': 'https://api.github.com/repos/dolphin-emu/dolphin/teams', 'hooks_url': 'https://api.github.com/repos/dolphin-emu/dolphin/hooks', 'issue_events_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/events{/number}', 'events_url': 'https://api.github.com/repos/dolphin-emu/dolphin/events', 'assignees_url': 'https://api.github.com/repos/dolphin-emu/dolphin/assignees{/user}', 'branches_url': 'https://api.github.com/repos/dolphin-emu/dolphin/branches{/branch}', 'tags_url': 'https://api.github.com/repos/dolphin-emu/dolphin/tags', 'blobs_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/blobs{/sha}', 'git_tags_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/tags{/sha}', 'git_refs_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/refs{/sha}', 'trees_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/trees{/sha}', 'statuses_url': 'https://api.github.com/repos/dolphin-emu/dolphin/statuses/{sha}', 'languages_url': 'https://api.github.com/repos/dolphin-emu/dolphin/languages', 'stargazers_url': 'https://api.github.com/repos/dolphin-emu/dolphin/stargazers', 'contributors_url': 'https://api.github.com/repos/dolphin-emu/dolphin/contributors', 'subscribers_url': 'https://api.github.com/repos/dolphin-emu/dolphin/subscribers', 'subscription_url': 'https://api.github.com/repos/dolphin-emu/dolphin/subscription', 'commits_url': 'https://api.github.com/repos/dolphin-emu/dolphin/commits{/sha}', 'git_commits_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/commits{/sha}', 'comments_url': 'https://api.github.com/repos/dolphin-emu/dolphin/comments{/number}', 'issue_comment_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/comments{/number}', 'contents_url': 'https://api.github.com/repos/dolphin-emu/dolphin/contents/{+path}', 'compare_url': 'https://api.github.com/repos/dolphin-emu/dolphin/compare/{base}...{head}', 'merges_url': 'https://api.github.com/repos/dolphin-emu/dolphin/merges', 'archive_url': 'https://api.github.com/repos/dolphin-emu/dolphin/{archive_format}{/ref}', 'downloads_url': 'https://api.github.com/repos/dolphin-emu/dolphin/downloads', 'issues_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues{/number}', 'pulls_url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls{/number}', 'milestones_url': 'https://api.github.com/repos/dolphin-emu/dolphin/milestones{/number}', 'notifications_url': 'https://api.github.com/repos/dolphin-emu/dolphin/notifications{?since,all,participating}', 'labels_url': 'https://api.github.com/repos/dolphin-emu/dolphin/labels{/name}', 'releases_url': 'https://api.github.com/repos/dolphin-emu/dolphin/releases{/id}', 'deployments_url': 'https://api.github.com/repos/dolphin-emu/dolphin/deployments', 'created_at': '2013-07-22T09:07:57Z', 'updated_at': '2026-07-17T13:03:27Z', 'pushed_at': '2026-07-15T20:58:02Z', 'git_url': 'git://github.com/dolphin-emu/dolphin.git', 'ssh_url': 'git@github.com:dolphin-emu/dolphin.git', 'clone_url': 'https://github.com/dolphin-emu/dolphin.git', 'svn_url': 'https://github.com/dolphin-emu/dolphin', 'homepage': 'https://dolphin-emu.org', 'size': 558444, 'stargazers_count': 15268, 'watchers_count': 15268, 'language': 'C++', 'has_issues': False, 'has_projects': False, 'has_downloads': True, 'has_wiki': True, 'has_pages': False, 'has_discussions': False, 'forks_count': 3162, 'mirror_url': None, 'archived': False, 'disabled': False, 'open_issues_count': 447, 'license': {'key': 'other', 'name': 'Other', 'spdx_id': 'NOASSERTION', 'url': None, 'node_id': 'MDc6TGljZW5zZTA='}, 'allow_forking': True, 'is_template': False, 'web_commit_signoff_required': False, 'has_pull_requests': True, 'pull_request_creation_policy': 'all', 'topics': ['cpp', 'emulation', 'emulator', 'gamecube', 'wii'], 'visibility': 'public', 'forks': 3162, 'open_issues': 447, 'watchers': 15268, 'default_branch': 'master', 'custom_properties': {}}, 'organization': {'login': 'dolphin-emu', 'id': 5050316, 'node_id': 'MDEyOk9yZ2FuaXphdGlvbjUwNTAzMTY=', 'url': 'https://api.github.com/orgs/dolphin-emu', 'repos_url': 'https://api.github.com/orgs/dolphin-emu/repos', 'events_url': 'https://api.github.com/orgs/dolphin-emu/events', 'hooks_url': 'https://api.github.com/orgs/dolphin-emu/hooks', 'issues_url': 'https://api.github.com/orgs/dolphin-emu/issues', 'members_url': 'https://api.github.com/orgs/dolphin-emu/members{/member}', 'public_members_url': 'https://api.github.com/orgs/dolphin-emu/public_members{/member}', 'avatar_url': 'https://avatars.githubusercontent.com/u/5050316?v=4', 'description': ''}, 'sender': {'login': 'thethiny', 'id': 6018214, 'node_id': 'MDQ6VXNlcjYwMTgyMTQ=', 'avatar_url': 'https://avatars.githubusercontent.com/u/6018214?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/thethiny', 'html_url': 'https://github.com/thethiny', 'followers_url': 'https://api.github.com/users/thethiny/followers', 'following_url': 'https://api.github.com/users/thethiny/following{/other_user}', 'gists_url': 'https://api.github.com/users/thethiny/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/thethiny/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/thethiny/subscriptions', 'organizations_url': 'https://api.github.com/users/thethiny/orgs', 'repos_url': 'https://api.github.com/users/thethiny/repos', 'events_url': 'https://api.github.com/users/thethiny/events{/privacy}', 'received_events_url': 'https://api.github.com/users/thethiny/received_events', 'type': 'User', 'user_view_type': 'public', 'site_admin': False}, 'installation': {'id': 35437981, 'node_id': 'MDIzOkludGVncmF0aW9uSW5zdGFsbGF0aW9uMzU0Mzc5ODE='}}, 'type': 'gh_issue_comment'}
2026-07-17T22:20:42.347164	{'source': 'ghhookparser', 'repo': 'dolphin-emu/dolphin', 'author': 'phire', 'action': 'created', 'id': 14731, 'title': 'Convert To WBFS Support', 'url': 'https://github.com/dolphin-emu/dolphin/pull/14731#issuecomment-5008023988', 'safe_author': True, 'body': "> You should expect a noticeable difference due to lossless having to check all the junk to be valid.\r\n\r\nThough, for the usecase of converting RVZ to wbfs, we already have all the junk blocks verified and indexed. Probably worth somehow exposing that information to the converter (in both directions). \r\n\r\nAlso, you probably should be using dolphin's existing `MultithreadedCompressor` infrastructure, already used by RVZ and GCZ. Sure, lossless wbfs doesn't do any explicit compression, but removing junk counts as compression and multithreadding would certainly speed it up. \r\n\r\nLet me know if you need any help working out how to hook into that infrastructure. ", 'raw': {'action': 'created', 'issue': {'url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/14731', 'repository_url': 'https://api.github.com/repos/dolphin-emu/dolphin', 'labels_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/14731/labels{/name}', 'comments_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/14731/comments', 'events_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/14731/events', 'html_url': 'https://github.com/dolphin-emu/dolphin/pull/14731', 'id': 4888393904, 'node_id': 'PR_kwDOALCn2M7x0I-2', 'number': 14731, 'title': 'Convert To WBFS Support', 'user': {'login': 'thethiny', 'id': 6018214, 'node_id': 'MDQ6VXNlcjYwMTgyMTQ=', 'avatar_url': 'https://avatars.githubusercontent.com/u/6018214?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/thethiny', 'html_url': 'https://github.com/thethiny', 'followers_url': 'https://api.github.com/users/thethiny/followers', 'following_url': 'https://api.github.com/users/thethiny/following{/other_user}', 'gists_url': 'https://api.github.com/users/thethiny/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/thethiny/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/thethiny/subscriptions', 'organizations_url': 'https://api.github.com/users/thethiny/orgs', 'repos_url': 'https://api.github.com/users/thethiny/repos', 'events_url': 'https://api.github.com/users/thethiny/events{/privacy}', 'received_events_url': 'https://api.github.com/users/thethiny/received_events', 'type': 'User', 'user_view_type': 'public', 'site_admin': False}, 'labels': [], 'state': 'open', 'locked': False, 'assignees': [], 'milestone': None, 'comments': 34, 'created_at': '2026-07-15T01:16:25Z', 'updated_at': '2026-07-17T22:20:40Z', 'closed_at': None, 'assignee': None, 'author_association': 'NONE', 'issue_field_values': [], 'type': None, 'active_lock_reason': None, 'draft': False, 'pull_request': {'url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/14731', 'html_url': 'https://github.com/dolphin-emu/dolphin/pull/14731', 'diff_url': 'https://github.com/dolphin-emu/dolphin/pull/14731.diff', 'patch_url': 'https://github.com/dolphin-emu/dolphin/pull/14731.patch', 'merged_at': None}, 'body': "This PR introduces Conversion **to** WBFS support. WBFS is the format that is used by USB Loaders on a real Wii device.\r\n\r\n## Design decisions & hardcoded values\r\nThe writer uses fixed sector sizes that match what [libwbfs (the reference implementation by kwiirk)](https://github.com/kwiirk/wbfs/blob/master/libwbfs/libwbfs.c#L128-L134) computes for a standard single-layer Wii disc. These 2 hardcodes are stable and work correctly across all my testings.\r\n- HD sector shift: 9 (512 bytes)\r\n- WBFS sector shift: 21 (2 MiB)\r\nThese are not configurable via the UI. All existing WBFS tools use these values, and since the aim is to support USB Loaders then this has been tested and it is working on a real Wii.\r\n\r\nConverting from WBFS is not enabled. The existing `WbfsFileReader` reports `DataSizeType::UpperBound`, and `ShouldAllowConversion()` requires `Accurate`. I am able to support this but since it was hardcoded by the Dolphin team I thought a discussion is warranted.\r\n\r\n## Testing\r\n- Verified with DolphinTool header and DolphinTool verify\r\n- Verified with wit FILETYPE and wit DUMP (Wiimm's ISO Tools recognizes valid WBFS structure, partitions, encryption)\r\n- Tested ISO to WBFS and RVZ to WBFS conversions\r\n- Output file sizes match Wii Backup Manager when scrubbing is enabled (~0.1% difference), works when scrubbing is disabled.\r\n- Output WBFS files play correctly in Dolphin\r\n- Output WBFS files play correctly on a real Wii using USB Loader GX e25c4f3\r\n", 'reactions': {'url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/14731/reactions', 'total_count': 2, '+1': 2, '-1': 0, 'laugh': 0, 'hooray': 0, 'confused': 0, 'heart': 0, 'rocket': 0, 'eyes': 0}, 'timeline_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/14731/timeline', 'performed_via_github_app': None, 'state_reason': None}, 'comment': {'url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/comments/5008023988', 'html_url': 'https://github.com/dolphin-emu/dolphin/pull/14731#issuecomment-5008023988', 'issue_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/14731', 'id': 5008023988, 'node_id': 'IC_kwDOALCn2M8AAAABKoBhtA', 'user': {'login': 'phire', 'id': 138484, 'node_id': 'MDQ6VXNlcjEzODQ4NA==', 'avatar_url': 'https://avatars.githubusercontent.com/u/138484?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/phire', 'html_url': 'https://github.com/phire', 'followers_url': 'https://api.github.com/users/phire/followers', 'following_url': 'https://api.github.com/users/phire/following{/other_user}', 'gists_url': 'https://api.github.com/users/phire/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/phire/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/phire/subscriptions', 'organizations_url': 'https://api.github.com/users/phire/orgs', 'repos_url': 'https://api.github.com/users/phire/repos', 'events_url': 'https://api.github.com/users/phire/events{/privacy}', 'received_events_url': 'https://api.github.com/users/phire/received_events', 'type': 'User', 'user_view_type': 'public', 'site_admin': False}, 'created_at': '2026-07-17T22:20:40Z', 'updated_at': '2026-07-17T22:20:40Z', 'body': "> You should expect a noticeable difference due to lossless having to check all the junk to be valid.\r\n\r\nThough, for the usecase of converting RVZ to wbfs, we already have all the junk blocks verified and indexed. Probably worth somehow exposing that information to the converter (in both directions). \r\n\r\nAlso, you probably should be using dolphin's existing `MultithreadedCompressor` infrastructure, already used by RVZ and GCZ. Sure, lossless wbfs doesn't do any explicit compression, but removing junk counts as compression and multithreadding would certainly speed it up. \r\n\r\nLet me know if you need any help working out how to hook into that infrastructure. ", 'author_association': 'MEMBER', 'reactions': {'url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/comments/5008023988/reactions', 'total_count': 0, '+1': 0, '-1': 0, 'laugh': 0, 'hooray': 0, 'confused': 0, 'heart': 0, 'rocket': 0, 'eyes': 0}, 'performed_via_github_app': None, 'minimized': None}, 'repository': {'id': 11577304, 'node_id': 'MDEwOlJlcG9zaXRvcnkxMTU3NzMwNA==', 'name': 'dolphin', 'full_name': 'dolphin-emu/dolphin', 'private': False, 'owner': {'login': 'dolphin-emu', 'id': 5050316, 'node_id': 'MDEyOk9yZ2FuaXphdGlvbjUwNTAzMTY=', 'avatar_url': 'https://avatars.githubusercontent.com/u/5050316?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/dolphin-emu', 'html_url': 'https://github.com/dolphin-emu', 'followers_url': 'https://api.github.com/users/dolphin-emu/followers', 'following_url': 'https://api.github.com/users/dolphin-emu/following{/other_user}', 'gists_url': 'https://api.github.com/users/dolphin-emu/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/dolphin-emu/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/dolphin-emu/subscriptions', 'organizations_url': 'https://api.github.com/users/dolphin-emu/orgs', 'repos_url': 'https://api.github.com/users/dolphin-emu/repos', 'events_url': 'https://api.github.com/users/dolphin-emu/events{/privacy}', 'received_events_url': 'https://api.github.com/users/dolphin-emu/received_events', 'type': 'Organization', 'user_view_type': 'public', 'site_admin': False}, 'html_url': 'https://github.com/dolphin-emu/dolphin', 'description': 'Dolphin is a GameCube / Wii emulator, allowing you to play games for these two platforms on PC with improvements.', 'fork': False, 'url': 'https://api.github.com/repos/dolphin-emu/dolphin', 'forks_url': 'https://api.github.com/repos/dolphin-emu/dolphin/forks', 'keys_url': 'https://api.github.com/repos/dolphin-emu/dolphin/keys{/key_id}', 'collaborators_url': 'https://api.github.com/repos/dolphin-emu/dolphin/collaborators{/collaborator}', 'teams_url': 'https://api.github.com/repos/dolphin-emu/dolphin/teams', 'hooks_url': 'https://api.github.com/repos/dolphin-emu/dolphin/hooks', 'issue_events_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/events{/number}', 'events_url': 'https://api.github.com/repos/dolphin-emu/dolphin/events', 'assignees_url': 'https://api.github.com/repos/dolphin-emu/dolphin/assignees{/user}', 'branches_url': 'https://api.github.com/repos/dolphin-emu/dolphin/branches{/branch}', 'tags_url': 'https://api.github.com/repos/dolphin-emu/dolphin/tags', 'blobs_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/blobs{/sha}', 'git_tags_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/tags{/sha}', 'git_refs_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/refs{/sha}', 'trees_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/trees{/sha}', 'statuses_url': 'https://api.github.com/repos/dolphin-emu/dolphin/statuses/{sha}', 'languages_url': 'https://api.github.com/repos/dolphin-emu/dolphin/languages', 'stargazers_url': 'https://api.github.com/repos/dolphin-emu/dolphin/stargazers', 'contributors_url': 'https://api.github.com/repos/dolphin-emu/dolphin/contributors', 'subscribers_url': 'https://api.github.com/repos/dolphin-emu/dolphin/subscribers', 'subscription_url': 'https://api.github.com/repos/dolphin-emu/dolphin/subscription', 'commits_url': 'https://api.github.com/repos/dolphin-emu/dolphin/commits{/sha}', 'git_commits_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/commits{/sha}', 'comments_url': 'https://api.github.com/repos/dolphin-emu/dolphin/comments{/number}', 'issue_comment_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/comments{/number}', 'contents_url': 'https://api.github.com/repos/dolphin-emu/dolphin/contents/{+path}', 'compare_url': 'https://api.github.com/repos/dolphin-emu/dolphin/compare/{base}...{head}', 'merges_url': 'https://api.github.com/repos/dolphin-emu/dolphin/merges', 'archive_url': 'https://api.github.com/repos/dolphin-emu/dolphin/{archive_format}{/ref}', 'downloads_url': 'https://api.github.com/repos/dolphin-emu/dolphin/downloads', 'issues_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues{/number}', 'pulls_url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls{/number}', 'milestones_url': 'https://api.github.com/repos/dolphin-emu/dolphin/milestones{/number}', 'notifications_url': 'https://api.github.com/repos/dolphin-emu/dolphin/notifications{?since,all,participating}', 'labels_url': 'https://api.github.com/repos/dolphin-emu/dolphin/labels{/name}', 'releases_url': 'https://api.github.com/repos/dolphin-emu/dolphin/releases{/id}', 'deployments_url': 'https://api.github.com/repos/dolphin-emu/dolphin/deployments', 'created_at': '2013-07-22T09:07:57Z', 'updated_at': '2026-07-17T13:03:27Z', 'pushed_at': '2026-07-15T20:58:02Z', 'git_url': 'git://github.com/dolphin-emu/dolphin.git', 'ssh_url': 'git@github.com:dolphin-emu/dolphin.git', 'clone_url': 'https://github.com/dolphin-emu/dolphin.git', 'svn_url': 'https://github.com/dolphin-emu/dolphin', 'homepage': 'https://dolphin-emu.org', 'size': 558444, 'stargazers_count': 15268, 'watchers_count': 15268, 'language': 'C++', 'has_issues': False, 'has_projects': False, 'has_downloads': True, 'has_wiki': True, 'has_pages': False, 'has_discussions': False, 'forks_count': 3162, 'mirror_url': None, 'archived': False, 'disabled': False, 'open_issues_count': 447, 'license': {'key': 'other', 'name': 'Other', 'spdx_id': 'NOASSERTION', 'url': None, 'node_id': 'MDc6TGljZW5zZTA='}, 'allow_forking': True, 'is_template': False, 'web_commit_signoff_required': False, 'has_pull_requests': True, 'pull_request_creation_policy': 'all', 'topics': ['cpp', 'emulation', 'emulator', 'gamecube', 'wii'], 'visibility': 'public', 'forks': 3162, 'open_issues': 447, 'watchers': 15268, 'default_branch': 'master', 'custom_properties': {}}, 'organization': {'login': 'dolphin-emu', 'id': 5050316, 'node_id': 'MDEyOk9yZ2FuaXphdGlvbjUwNTAzMTY=', 'url': 'https://api.github.com/orgs/dolphin-emu', 'repos_url': 'https://api.github.com/orgs/dolphin-emu/repos', 'events_url': 'https://api.github.com/orgs/dolphin-emu/events', 'hooks_url': 'https://api.github.com/orgs/dolphin-emu/hooks', 'issues_url': 'https://api.github.com/orgs/dolphin-emu/issues', 'members_url': 'https://api.github.com/orgs/dolphin-emu/members{/member}', 'public_members_url': 'https://api.github.com/orgs/dolphin-emu/public_members{/member}', 'avatar_url': 'https://avatars.githubusercontent.com/u/5050316?v=4', 'description': ''}, 'sender': {'login': 'phire', 'id': 138484, 'node_id': 'MDQ6VXNlcjEzODQ4NA==', 'avatar_url': 'https://avatars.githubusercontent.com/u/138484?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/phire', 'html_url': 'https://github.com/phire', 'followers_url': 'https://api.github.com/users/phire/followers', 'following_url': 'https://api.github.com/users/phire/following{/other_user}', 'gists_url': 'https://api.github.com/users/phire/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/phire/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/phire/subscriptions', 'organizations_url': 'https://api.github.com/users/phire/orgs', 'repos_url': 'https://api.github.com/users/phire/repos', 'events_url': 'https://api.github.com/users/phire/events{/privacy}', 'received_events_url': 'https://api.github.com/users/phire/received_events', 'type': 'User', 'user_view_type': 'public', 'site_admin': False}, 'installation': {'id': 35437981, 'node_id': 'MDIzOkludGVncmF0aW9uSW5zdGFsbGF0aW9uMzU0Mzc5ODE='}}, 'type': 'gh_issue_comment'}
2026-07-17T21:51:14.134034	{'source': 'ghhookparser', 'repo': 'dolphin-emu/dolphin', 'author': 'Nanook', 'action': 'created', 'id': 14731, 'title': 'Convert To WBFS Support', 'url': 'https://github.com/dolphin-emu/dolphin/pull/14731#issuecomment-5007796942', 'safe_author': False, 'body': 'Test Jakers as it has 1 bit of invalid junk beneath valid encryption', 'raw': {'action': 'created', 'issue': {'url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/14731', 'repository_url': 'https://api.github.com/repos/dolphin-emu/dolphin', 'labels_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/14731/labels{/name}', 'comments_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/14731/comments', 'events_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/14731/events', 'html_url': 'https://github.com/dolphin-emu/dolphin/pull/14731', 'id': 4888393904, 'node_id': 'PR_kwDOALCn2M7x0I-2', 'number': 14731, 'title': 'Convert To WBFS Support', 'user': {'login': 'thethiny', 'id': 6018214, 'node_id': 'MDQ6VXNlcjYwMTgyMTQ=', 'avatar_url': 'https://avatars.githubusercontent.com/u/6018214?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/thethiny', 'html_url': 'https://github.com/thethiny', 'followers_url': 'https://api.github.com/users/thethiny/followers', 'following_url': 'https://api.github.com/users/thethiny/following{/other_user}', 'gists_url': 'https://api.github.com/users/thethiny/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/thethiny/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/thethiny/subscriptions', 'organizations_url': 'https://api.github.com/users/thethiny/orgs', 'repos_url': 'https://api.github.com/users/thethiny/repos', 'events_url': 'https://api.github.com/users/thethiny/events{/privacy}', 'received_events_url': 'https://api.github.com/users/thethiny/received_events', 'type': 'User', 'user_view_type': 'public', 'site_admin': False}, 'labels': [], 'state': 'open', 'locked': False, 'assignees': [], 'milestone': None, 'comments': 33, 'created_at': '2026-07-15T01:16:25Z', 'updated_at': '2026-07-17T21:51:11Z', 'closed_at': None, 'assignee': None, 'author_association': 'NONE', 'issue_field_values': [], 'type': None, 'active_lock_reason': None, 'draft': False, 'pull_request': {'url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/14731', 'html_url': 'https://github.com/dolphin-emu/dolphin/pull/14731', 'diff_url': 'https://github.com/dolphin-emu/dolphin/pull/14731.diff', 'patch_url': 'https://github.com/dolphin-emu/dolphin/pull/14731.patch', 'merged_at': None}, 'body': "This PR introduces Conversion **to** WBFS support. WBFS is the format that is used by USB Loaders on a real Wii device.\r\n\r\n## Design decisions & hardcoded values\r\nThe writer uses fixed sector sizes that match what [libwbfs (the reference implementation by kwiirk)](https://github.com/kwiirk/wbfs/blob/master/libwbfs/libwbfs.c#L128-L134) computes for a standard single-layer Wii disc. These 2 hardcodes are stable and work correctly across all my testings.\r\n- HD sector shift: 9 (512 bytes)\r\n- WBFS sector shift: 21 (2 MiB)\r\nThese are not configurable via the UI. All existing WBFS tools use these values, and since the aim is to support USB Loaders then this has been tested and it is working on a real Wii.\r\n\r\nConverting from WBFS is not enabled. The existing `WbfsFileReader` reports `DataSizeType::UpperBound`, and `ShouldAllowConversion()` requires `Accurate`. I am able to support this but since it was hardcoded by the Dolphin team I thought a discussion is warranted.\r\n\r\n## Testing\r\n- Verified with DolphinTool header and DolphinTool verify\r\n- Verified with wit FILETYPE and wit DUMP (Wiimm's ISO Tools recognizes valid WBFS structure, partitions, encryption)\r\n- Tested ISO to WBFS and RVZ to WBFS conversions\r\n- Output file sizes match Wii Backup Manager when scrubbing is enabled (~0.1% difference), works when scrubbing is disabled.\r\n- Output WBFS files play correctly in Dolphin\r\n- Output WBFS files play correctly on a real Wii using USB Loader GX e25c4f3\r\n", 'reactions': {'url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/14731/reactions', 'total_count': 2, '+1': 2, '-1': 0, 'laugh': 0, 'hooray': 0, 'confused': 0, 'heart': 0, 'rocket': 0, 'eyes': 0}, 'timeline_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/14731/timeline', 'performed_via_github_app': None, 'state_reason': None}, 'comment': {'url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/comments/5007796942', 'html_url': 'https://github.com/dolphin-emu/dolphin/pull/14731#issuecomment-5007796942', 'issue_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/14731', 'id': 5007796942, 'node_id': 'IC_kwDOALCn2M8AAAABKnzqzg', 'user': {'login': 'Nanook', 'id': 188841, 'node_id': 'MDQ6VXNlcjE4ODg0MQ==', 'avatar_url': 'https://avatars.githubusercontent.com/u/188841?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/Nanook', 'html_url': 'https://github.com/Nanook', 'followers_url': 'https://api.github.com/users/Nanook/followers', 'following_url': 'https://api.github.com/users/Nanook/following{/other_user}', 'gists_url': 'https://api.github.com/users/Nanook/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/Nanook/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/Nanook/subscriptions', 'organizations_url': 'https://api.github.com/users/Nanook/orgs', 'repos_url': 'https://api.github.com/users/Nanook/repos', 'events_url': 'https://api.github.com/users/Nanook/events{/privacy}', 'received_events_url': 'https://api.github.com/users/Nanook/received_events', 'type': 'User', 'user_view_type': 'public', 'site_admin': False}, 'created_at': '2026-07-17T21:51:11Z', 'updated_at': '2026-07-17T21:51:11Z', 'body': 'Test Jakers as it has 1 bit of invalid junk beneath valid encryption', 'author_association': 'NONE', 'reactions': {'url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/comments/5007796942/reactions', 'total_count': 0, '+1': 0, '-1': 0, 'laugh': 0, 'hooray': 0, 'confused': 0, 'heart': 0, 'rocket': 0, 'eyes': 0}, 'performed_via_github_app': None, 'minimized': None}, 'repository': {'id': 11577304, 'node_id': 'MDEwOlJlcG9zaXRvcnkxMTU3NzMwNA==', 'name': 'dolphin', 'full_name': 'dolphin-emu/dolphin', 'private': False, 'owner': {'login': 'dolphin-emu', 'id': 5050316, 'node_id': 'MDEyOk9yZ2FuaXphdGlvbjUwNTAzMTY=', 'avatar_url': 'https://avatars.githubusercontent.com/u/5050316?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/dolphin-emu', 'html_url': 'https://github.com/dolphin-emu', 'followers_url': 'https://api.github.com/users/dolphin-emu/followers', 'following_url': 'https://api.github.com/users/dolphin-emu/following{/other_user}', 'gists_url': 'https://api.github.com/users/dolphin-emu/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/dolphin-emu/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/dolphin-emu/subscriptions', 'organizations_url': 'https://api.github.com/users/dolphin-emu/orgs', 'repos_url': 'https://api.github.com/users/dolphin-emu/repos', 'events_url': 'https://api.github.com/users/dolphin-emu/events{/privacy}', 'received_events_url': 'https://api.github.com/users/dolphin-emu/received_events', 'type': 'Organization', 'user_view_type': 'public', 'site_admin': False}, 'html_url': 'https://github.com/dolphin-emu/dolphin', 'description': 'Dolphin is a GameCube / Wii emulator, allowing you to play games for these two platforms on PC with improvements.', 'fork': False, 'url': 'https://api.github.com/repos/dolphin-emu/dolphin', 'forks_url': 'https://api.github.com/repos/dolphin-emu/dolphin/forks', 'keys_url': 'https://api.github.com/repos/dolphin-emu/dolphin/keys{/key_id}', 'collaborators_url': 'https://api.github.com/repos/dolphin-emu/dolphin/collaborators{/collaborator}', 'teams_url': 'https://api.github.com/repos/dolphin-emu/dolphin/teams', 'hooks_url': 'https://api.github.com/repos/dolphin-emu/dolphin/hooks', 'issue_events_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/events{/number}', 'events_url': 'https://api.github.com/repos/dolphin-emu/dolphin/events', 'assignees_url': 'https://api.github.com/repos/dolphin-emu/dolphin/assignees{/user}', 'branches_url': 'https://api.github.com/repos/dolphin-emu/dolphin/branches{/branch}', 'tags_url': 'https://api.github.com/repos/dolphin-emu/dolphin/tags', 'blobs_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/blobs{/sha}', 'git_tags_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/tags{/sha}', 'git_refs_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/refs{/sha}', 'trees_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/trees{/sha}', 'statuses_url': 'https://api.github.com/repos/dolphin-emu/dolphin/statuses/{sha}', 'languages_url': 'https://api.github.com/repos/dolphin-emu/dolphin/languages', 'stargazers_url': 'https://api.github.com/repos/dolphin-emu/dolphin/stargazers', 'contributors_url': 'https://api.github.com/repos/dolphin-emu/dolphin/contributors', 'subscribers_url': 'https://api.github.com/repos/dolphin-emu/dolphin/subscribers', 'subscription_url': 'https://api.github.com/repos/dolphin-emu/dolphin/subscription', 'commits_url': 'https://api.github.com/repos/dolphin-emu/dolphin/commits{/sha}', 'git_commits_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/commits{/sha}', 'comments_url': 'https://api.github.com/repos/dolphin-emu/dolphin/comments{/number}', 'issue_comment_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/comments{/number}', 'contents_url': 'https://api.github.com/repos/dolphin-emu/dolphin/contents/{+path}', 'compare_url': 'https://api.github.com/repos/dolphin-emu/dolphin/compare/{base}...{head}', 'merges_url': 'https://api.github.com/repos/dolphin-emu/dolphin/merges', 'archive_url': 'https://api.github.com/repos/dolphin-emu/dolphin/{archive_format}{/ref}', 'downloads_url': 'https://api.github.com/repos/dolphin-emu/dolphin/downloads', 'issues_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues{/number}', 'pulls_url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls{/number}', 'milestones_url': 'https://api.github.com/repos/dolphin-emu/dolphin/milestones{/number}', 'notifications_url': 'https://api.github.com/repos/dolphin-emu/dolphin/notifications{?since,all,participating}', 'labels_url': 'https://api.github.com/repos/dolphin-emu/dolphin/labels{/name}', 'releases_url': 'https://api.github.com/repos/dolphin-emu/dolphin/releases{/id}', 'deployments_url': 'https://api.github.com/repos/dolphin-emu/dolphin/deployments', 'created_at': '2013-07-22T09:07:57Z', 'updated_at': '2026-07-17T13:03:27Z', 'pushed_at': '2026-07-15T20:58:02Z', 'git_url': 'git://github.com/dolphin-emu/dolphin.git', 'ssh_url': 'git@github.com:dolphin-emu/dolphin.git', 'clone_url': 'https://github.com/dolphin-emu/dolphin.git', 'svn_url': 'https://github.com/dolphin-emu/dolphin', 'homepage': 'https://dolphin-emu.org', 'size': 558444, 'stargazers_count': 15268, 'watchers_count': 15268, 'language': 'C++', 'has_issues': False, 'has_projects': False, 'has_downloads': True, 'has_wiki': True, 'has_pages': False, 'has_discussions': False, 'forks_count': 3162, 'mirror_url': None, 'archived': False, 'disabled': False, 'open_issues_count': 447, 'license': {'key': 'other', 'name': 'Other', 'spdx_id': 'NOASSERTION', 'url': None, 'node_id': 'MDc6TGljZW5zZTA='}, 'allow_forking': True, 'is_template': False, 'web_commit_signoff_required': False, 'has_pull_requests': True, 'pull_request_creation_policy': 'all', 'topics': ['cpp', 'emulation', 'emulator', 'gamecube', 'wii'], 'visibility': 'public', 'forks': 3162, 'open_issues': 447, 'watchers': 15268, 'default_branch': 'master', 'custom_properties': {}}, 'organization': {'login': 'dolphin-emu', 'id': 5050316, 'node_id': 'MDEyOk9yZ2FuaXphdGlvbjUwNTAzMTY=', 'url': 'https://api.github.com/orgs/dolphin-emu', 'repos_url': 'https://api.github.com/orgs/dolphin-emu/repos', 'events_url': 'https://api.github.com/orgs/dolphin-emu/events', 'hooks_url': 'https://api.github.com/orgs/dolphin-emu/hooks', 'issues_url': 'https://api.github.com/orgs/dolphin-emu/issues', 'members_url': 'https://api.github.com/orgs/dolphin-emu/members{/member}', 'public_members_url': 'https://api.github.com/orgs/dolphin-emu/public_members{/member}', 'avatar_url': 'https://avatars.githubusercontent.com/u/5050316?v=4', 'description': ''}, 'sender': {'login': 'Nanook', 'id': 188841, 'node_id': 'MDQ6VXNlcjE4ODg0MQ==', 'avatar_url': 'https://avatars.githubusercontent.com/u/188841?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/Nanook', 'html_url': 'https://github.com/Nanook', 'followers_url': 'https://api.github.com/users/Nanook/followers', 'following_url': 'https://api.github.com/users/Nanook/following{/other_user}', 'gists_url': 'https://api.github.com/users/Nanook/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/Nanook/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/Nanook/subscriptions', 'organizations_url': 'https://api.github.com/users/Nanook/orgs', 'repos_url': 'https://api.github.com/users/Nanook/repos', 'events_url': 'https://api.github.com/users/Nanook/events{/privacy}', 'received_events_url': 'https://api.github.com/users/Nanook/received_events', 'type': 'User', 'user_view_type': 'public', 'site_admin': False}, 'installation': {'id': 35437981, 'node_id': 'MDIzOkludGVncmF0aW9uSW5zdGFsbGF0aW9uMzU0Mzc5ODE='}}, 'type': 'gh_issue_comment'}
2026-07-17T21:49:27.466615	{'source': 'ghhookparser', 'repo': 'dolphin-emu/dolphin', 'author': 'Nanook', 'action': 'created', 'id': 14731, 'title': 'Convert To WBFS Support', 'url': 'https://github.com/dolphin-emu/dolphin/pull/14731#issuecomment-5007781879', 'safe_author': False, 'body': "> > Happy to chip in if there's anything still outstanding\r\n> \r\n> I will push today's work in a bit to this branch but I'm doing some benchmarking first, and u can take a look if you're interested? I noticed difference in conversion speed between lossy and lossless wbfs and I think you might be able to have an opinion, but I need to confirm all benchmarks are accurate first to be able to produce a reproduceable report.\r\n\r\nYou should expect a noticeable difference due to lossless having to check all the junk to be valid. Lossy can just read the fst and skip the gaps.", 'raw': {'action': 'created', 'issue': {'url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/14731', 'repository_url': 'https://api.github.com/repos/dolphin-emu/dolphin', 'labels_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/14731/labels{/name}', 'comments_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/14731/comments', 'events_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/14731/events', 'html_url': 'https://github.com/dolphin-emu/dolphin/pull/14731', 'id': 4888393904, 'node_id': 'PR_kwDOALCn2M7x0I-2', 'number': 14731, 'title': 'Convert To WBFS Support', 'user': {'login': 'thethiny', 'id': 6018214, 'node_id': 'MDQ6VXNlcjYwMTgyMTQ=', 'avatar_url': 'https://avatars.githubusercontent.com/u/6018214?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/thethiny', 'html_url': 'https://github.com/thethiny', 'followers_url': 'https://api.github.com/users/thethiny/followers', 'following_url': 'https://api.github.com/users/thethiny/following{/other_user}', 'gists_url': 'https://api.github.com/users/thethiny/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/thethiny/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/thethiny/subscriptions', 'organizations_url': 'https://api.github.com/users/thethiny/orgs', 'repos_url': 'https://api.github.com/users/thethiny/repos', 'events_url': 'https://api.github.com/users/thethiny/events{/privacy}', 'received_events_url': 'https://api.github.com/users/thethiny/received_events', 'type': 'User', 'user_view_type': 'public', 'site_admin': False}, 'labels': [], 'state': 'open', 'locked': False, 'assignees': [], 'milestone': None, 'comments': 32, 'created_at': '2026-07-15T01:16:25Z', 'updated_at': '2026-07-17T21:49:25Z', 'closed_at': None, 'assignee': None, 'author_association': 'NONE', 'issue_field_values': [], 'type': None, 'active_lock_reason': None, 'draft': False, 'pull_request': {'url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/14731', 'html_url': 'https://github.com/dolphin-emu/dolphin/pull/14731', 'diff_url': 'https://github.com/dolphin-emu/dolphin/pull/14731.diff', 'patch_url': 'https://github.com/dolphin-emu/dolphin/pull/14731.patch', 'merged_at': None}, 'body': "This PR introduces Conversion **to** WBFS support. WBFS is the format that is used by USB Loaders on a real Wii device.\r\n\r\n## Design decisions & hardcoded values\r\nThe writer uses fixed sector sizes that match what [libwbfs (the reference implementation by kwiirk)](https://github.com/kwiirk/wbfs/blob/master/libwbfs/libwbfs.c#L128-L134) computes for a standard single-layer Wii disc. These 2 hardcodes are stable and work correctly across all my testings.\r\n- HD sector shift: 9 (512 bytes)\r\n- WBFS sector shift: 21 (2 MiB)\r\nThese are not configurable via the UI. All existing WBFS tools use these values, and since the aim is to support USB Loaders then this has been tested and it is working on a real Wii.\r\n\r\nConverting from WBFS is not enabled. The existing `WbfsFileReader` reports `DataSizeType::UpperBound`, and `ShouldAllowConversion()` requires `Accurate`. I am able to support this but since it was hardcoded by the Dolphin team I thought a discussion is warranted.\r\n\r\n## Testing\r\n- Verified with DolphinTool header and DolphinTool verify\r\n- Verified with wit FILETYPE and wit DUMP (Wiimm's ISO Tools recognizes valid WBFS structure, partitions, encryption)\r\n- Tested ISO to WBFS and RVZ to WBFS conversions\r\n- Output file sizes match Wii Backup Manager when scrubbing is enabled (~0.1% difference), works when scrubbing is disabled.\r\n- Output WBFS files play correctly in Dolphin\r\n- Output WBFS files play correctly on a real Wii using USB Loader GX e25c4f3\r\n", 'reactions': {'url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/14731/reactions', 'total_count': 2, '+1': 2, '-1': 0, 'laugh': 0, 'hooray': 0, 'confused': 0, 'heart': 0, 'rocket': 0, 'eyes': 0}, 'timeline_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/14731/timeline', 'performed_via_github_app': None, 'state_reason': None}, 'comment': {'url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/comments/5007781879', 'html_url': 'https://github.com/dolphin-emu/dolphin/pull/14731#issuecomment-5007781879', 'issue_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/14731', 'id': 5007781879, 'node_id': 'IC_kwDOALCn2M8AAAABKnyv9w', 'user': {'login': 'Nanook', 'id': 188841, 'node_id': 'MDQ6VXNlcjE4ODg0MQ==', 'avatar_url': 'https://avatars.githubusercontent.com/u/188841?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/Nanook', 'html_url': 'https://github.com/Nanook', 'followers_url': 'https://api.github.com/users/Nanook/followers', 'following_url': 'https://api.github.com/users/Nanook/following{/other_user}', 'gists_url': 'https://api.github.com/users/Nanook/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/Nanook/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/Nanook/subscriptions', 'organizations_url': 'https://api.github.com/users/Nanook/orgs', 'repos_url': 'https://api.github.com/users/Nanook/repos', 'events_url': 'https://api.github.com/users/Nanook/events{/privacy}', 'received_events_url': 'https://api.github.com/users/Nanook/received_events', 'type': 'User', 'user_view_type': 'public', 'site_admin': False}, 'created_at': '2026-07-17T21:49:25Z', 'updated_at': '2026-07-17T21:49:25Z', 'body': "> > Happy to chip in if there's anything still outstanding\r\n> \r\n> I will push today's work in a bit to this branch but I'm doing some benchmarking first, and u can take a look if you're interested? I noticed difference in conversion speed between lossy and lossless wbfs and I think you might be able to have an opinion, but I need to confirm all benchmarks are accurate first to be able to produce a reproduceable report.\r\n\r\nYou should expect a noticeable difference due to lossless having to check all the junk to be valid. Lossy can just read the fst and skip the gaps.", 'author_association': 'NONE', 'reactions': {'url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/comments/5007781879/reactions', 'total_count': 0, '+1': 0, '-1': 0, 'laugh': 0, 'hooray': 0, 'confused': 0, 'heart': 0, 'rocket': 0, 'eyes': 0}, 'performed_via_github_app': None, 'minimized': None}, 'repository': {'id': 11577304, 'node_id': 'MDEwOlJlcG9zaXRvcnkxMTU3NzMwNA==', 'name': 'dolphin', 'full_name': 'dolphin-emu/dolphin', 'private': False, 'owner': {'login': 'dolphin-emu', 'id': 5050316, 'node_id': 'MDEyOk9yZ2FuaXphdGlvbjUwNTAzMTY=', 'avatar_url': 'https://avatars.githubusercontent.com/u/5050316?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/dolphin-emu', 'html_url': 'https://github.com/dolphin-emu', 'followers_url': 'https://api.github.com/users/dolphin-emu/followers', 'following_url': 'https://api.github.com/users/dolphin-emu/following{/other_user}', 'gists_url': 'https://api.github.com/users/dolphin-emu/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/dolphin-emu/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/dolphin-emu/subscriptions', 'organizations_url': 'https://api.github.com/users/dolphin-emu/orgs', 'repos_url': 'https://api.github.com/users/dolphin-emu/repos', 'events_url': 'https://api.github.com/users/dolphin-emu/events{/privacy}', 'received_events_url': 'https://api.github.com/users/dolphin-emu/received_events', 'type': 'Organization', 'user_view_type': 'public', 'site_admin': False}, 'html_url': 'https://github.com/dolphin-emu/dolphin', 'description': 'Dolphin is a GameCube / Wii emulator, allowing you to play games for these two platforms on PC with improvements.', 'fork': False, 'url': 'https://api.github.com/repos/dolphin-emu/dolphin', 'forks_url': 'https://api.github.com/repos/dolphin-emu/dolphin/forks', 'keys_url': 'https://api.github.com/repos/dolphin-emu/dolphin/keys{/key_id}', 'collaborators_url': 'https://api.github.com/repos/dolphin-emu/dolphin/collaborators{/collaborator}', 'teams_url': 'https://api.github.com/repos/dolphin-emu/dolphin/teams', 'hooks_url': 'https://api.github.com/repos/dolphin-emu/dolphin/hooks', 'issue_events_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/events{/number}', 'events_url': 'https://api.github.com/repos/dolphin-emu/dolphin/events', 'assignees_url': 'https://api.github.com/repos/dolphin-emu/dolphin/assignees{/user}', 'branches_url': 'https://api.github.com/repos/dolphin-emu/dolphin/branches{/branch}', 'tags_url': 'https://api.github.com/repos/dolphin-emu/dolphin/tags', 'blobs_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/blobs{/sha}', 'git_tags_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/tags{/sha}', 'git_refs_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/refs{/sha}', 'trees_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/trees{/sha}', 'statuses_url': 'https://api.github.com/repos/dolphin-emu/dolphin/statuses/{sha}', 'languages_url': 'https://api.github.com/repos/dolphin-emu/dolphin/languages', 'stargazers_url': 'https://api.github.com/repos/dolphin-emu/dolphin/stargazers', 'contributors_url': 'https://api.github.com/repos/dolphin-emu/dolphin/contributors', 'subscribers_url': 'https://api.github.com/repos/dolphin-emu/dolphin/subscribers', 'subscription_url': 'https://api.github.com/repos/dolphin-emu/dolphin/subscription', 'commits_url': 'https://api.github.com/repos/dolphin-emu/dolphin/commits{/sha}', 'git_commits_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/commits{/sha}', 'comments_url': 'https://api.github.com/repos/dolphin-emu/dolphin/comments{/number}', 'issue_comment_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/comments{/number}', 'contents_url': 'https://api.github.com/repos/dolphin-emu/dolphin/contents/{+path}', 'compare_url': 'https://api.github.com/repos/dolphin-emu/dolphin/compare/{base}...{head}', 'merges_url': 'https://api.github.com/repos/dolphin-emu/dolphin/merges', 'archive_url': 'https://api.github.com/repos/dolphin-emu/dolphin/{archive_format}{/ref}', 'downloads_url': 'https://api.github.com/repos/dolphin-emu/dolphin/downloads', 'issues_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues{/number}', 'pulls_url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls{/number}', 'milestones_url': 'https://api.github.com/repos/dolphin-emu/dolphin/milestones{/number}', 'notifications_url': 'https://api.github.com/repos/dolphin-emu/dolphin/notifications{?since,all,participating}', 'labels_url': 'https://api.github.com/repos/dolphin-emu/dolphin/labels{/name}', 'releases_url': 'https://api.github.com/repos/dolphin-emu/dolphin/releases{/id}', 'deployments_url': 'https://api.github.com/repos/dolphin-emu/dolphin/deployments', 'created_at': '2013-07-22T09:07:57Z', 'updated_at': '2026-07-17T13:03:27Z', 'pushed_at': '2026-07-15T20:58:02Z', 'git_url': 'git://github.com/dolphin-emu/dolphin.git', 'ssh_url': 'git@github.com:dolphin-emu/dolphin.git', 'clone_url': 'https://github.com/dolphin-emu/dolphin.git', 'svn_url': 'https://github.com/dolphin-emu/dolphin', 'homepage': 'https://dolphin-emu.org', 'size': 558444, 'stargazers_count': 15268, 'watchers_count': 15268, 'language': 'C++', 'has_issues': False, 'has_projects': False, 'has_downloads': True, 'has_wiki': True, 'has_pages': False, 'has_discussions': False, 'forks_count': 3162, 'mirror_url': None, 'archived': False, 'disabled': False, 'open_issues_count': 447, 'license': {'key': 'other', 'name': 'Other', 'spdx_id': 'NOASSERTION', 'url': None, 'node_id': 'MDc6TGljZW5zZTA='}, 'allow_forking': True, 'is_template': False, 'web_commit_signoff_required': False, 'has_pull_requests': True, 'pull_request_creation_policy': 'all', 'topics': ['cpp', 'emulation', 'emulator', 'gamecube', 'wii'], 'visibility': 'public', 'forks': 3162, 'open_issues': 447, 'watchers': 15268, 'default_branch': 'master', 'custom_properties': {}}, 'organization': {'login': 'dolphin-emu', 'id': 5050316, 'node_id': 'MDEyOk9yZ2FuaXphdGlvbjUwNTAzMTY=', 'url': 'https://api.github.com/orgs/dolphin-emu', 'repos_url': 'https://api.github.com/orgs/dolphin-emu/repos', 'events_url': 'https://api.github.com/orgs/dolphin-emu/events', 'hooks_url': 'https://api.github.com/orgs/dolphin-emu/hooks', 'issues_url': 'https://api.github.com/orgs/dolphin-emu/issues', 'members_url': 'https://api.github.com/orgs/dolphin-emu/members{/member}', 'public_members_url': 'https://api.github.com/orgs/dolphin-emu/public_members{/member}', 'avatar_url': 'https://avatars.githubusercontent.com/u/5050316?v=4', 'description': ''}, 'sender': {'login': 'Nanook', 'id': 188841, 'node_id': 'MDQ6VXNlcjE4ODg0MQ==', 'avatar_url': 'https://avatars.githubusercontent.com/u/188841?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/Nanook', 'html_url': 'https://github.com/Nanook', 'followers_url': 'https://api.github.com/users/Nanook/followers', 'following_url': 'https://api.github.com/users/Nanook/following{/other_user}', 'gists_url': 'https://api.github.com/users/Nanook/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/Nanook/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/Nanook/subscriptions', 'organizations_url': 'https://api.github.com/users/Nanook/orgs', 'repos_url': 'https://api.github.com/users/Nanook/repos', 'events_url': 'https://api.github.com/users/Nanook/events{/privacy}', 'received_events_url': 'https://api.github.com/users/Nanook/received_events', 'type': 'User', 'user_view_type': 'public', 'site_admin': False}, 'installation': {'id': 35437981, 'node_id': 'MDIzOkludGVncmF0aW9uSW5zdGFsbGF0aW9uMzU0Mzc5ODE='}}, 'type': 'gh_issue_comment'}
2026-07-17T21:03:15.638941	{'source': 'ghhookparser', 'repo': 'dolphin-emu/dolphin', 'author': 'thethiny', 'action': 'created', 'id': 14731, 'title': 'Convert To WBFS Support', 'url': 'https://github.com/dolphin-emu/dolphin/pull/14731#issuecomment-5007452123', 'safe_author': False, 'body': "> Happy to chip in if there's anything still outstanding\r\n\r\nI will push today's work in a bit to this branch but I'm doing some benchmarking first, and u can take a look if you're interested? I noticed difference in conversion speed between lossy and lossless wbfs and I think you might be able to have an opinion, but I need to confirm all benchmarks are accurate first to be able to produce a reproduceable report.", 'raw': {'action': 'created', 'issue': {'url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/14731', 'repository_url': 'https://api.github.com/repos/dolphin-emu/dolphin', 'labels_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/14731/labels{/name}', 'comments_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/14731/comments', 'events_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/14731/events', 'html_url': 'https://github.com/dolphin-emu/dolphin/pull/14731', 'id': 4888393904, 'node_id': 'PR_kwDOALCn2M7x0I-2', 'number': 14731, 'title': 'Convert To WBFS Support', 'user': {'login': 'thethiny', 'id': 6018214, 'node_id': 'MDQ6VXNlcjYwMTgyMTQ=', 'avatar_url': 'https://avatars.githubusercontent.com/u/6018214?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/thethiny', 'html_url': 'https://github.com/thethiny', 'followers_url': 'https://api.github.com/users/thethiny/followers', 'following_url': 'https://api.github.com/users/thethiny/following{/other_user}', 'gists_url': 'https://api.github.com/users/thethiny/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/thethiny/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/thethiny/subscriptions', 'organizations_url': 'https://api.github.com/users/thethiny/orgs', 'repos_url': 'https://api.github.com/users/thethiny/repos', 'events_url': 'https://api.github.com/users/thethiny/events{/privacy}', 'received_events_url': 'https://api.github.com/users/thethiny/received_events', 'type': 'User', 'user_view_type': 'public', 'site_admin': False}, 'labels': [], 'state': 'open', 'locked': False, 'assignees': [], 'milestone': None, 'comments': 31, 'created_at': '2026-07-15T01:16:25Z', 'updated_at': '2026-07-17T21:03:14Z', 'closed_at': None, 'assignee': None, 'author_association': 'NONE', 'issue_field_values': [], 'type': None, 'active_lock_reason': None, 'draft': False, 'pull_request': {'url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/14731', 'html_url': 'https://github.com/dolphin-emu/dolphin/pull/14731', 'diff_url': 'https://github.com/dolphin-emu/dolphin/pull/14731.diff', 'patch_url': 'https://github.com/dolphin-emu/dolphin/pull/14731.patch', 'merged_at': None}, 'body': "This PR introduces Conversion **to** WBFS support. WBFS is the format that is used by USB Loaders on a real Wii device.\r\n\r\n## Design decisions & hardcoded values\r\nThe writer uses fixed sector sizes that match what [libwbfs (the reference implementation by kwiirk)](https://github.com/kwiirk/wbfs/blob/master/libwbfs/libwbfs.c#L128-L134) computes for a standard single-layer Wii disc. These 2 hardcodes are stable and work correctly across all my testings.\r\n- HD sector shift: 9 (512 bytes)\r\n- WBFS sector shift: 21 (2 MiB)\r\nThese are not configurable via the UI. All existing WBFS tools use these values, and since the aim is to support USB Loaders then this has been tested and it is working on a real Wii.\r\n\r\nConverting from WBFS is not enabled. The existing `WbfsFileReader` reports `DataSizeType::UpperBound`, and `ShouldAllowConversion()` requires `Accurate`. I am able to support this but since it was hardcoded by the Dolphin team I thought a discussion is warranted.\r\n\r\n## Testing\r\n- Verified with DolphinTool header and DolphinTool verify\r\n- Verified with wit FILETYPE and wit DUMP (Wiimm's ISO Tools recognizes valid WBFS structure, partitions, encryption)\r\n- Tested ISO to WBFS and RVZ to WBFS conversions\r\n- Output file sizes match Wii Backup Manager when scrubbing is enabled (~0.1% difference), works when scrubbing is disabled.\r\n- Output WBFS files play correctly in Dolphin\r\n- Output WBFS files play correctly on a real Wii using USB Loader GX e25c4f3\r\n", 'reactions': {'url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/14731/reactions', 'total_count': 2, '+1': 2, '-1': 0, 'laugh': 0, 'hooray': 0, 'confused': 0, 'heart': 0, 'rocket': 0, 'eyes': 0}, 'timeline_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/14731/timeline', 'performed_via_github_app': None, 'state_reason': None}, 'comment': {'url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/comments/5007452123', 'html_url': 'https://github.com/dolphin-emu/dolphin/pull/14731#issuecomment-5007452123', 'issue_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/14731', 'id': 5007452123, 'node_id': 'IC_kwDOALCn2M8AAAABKnen2w', 'user': {'login': 'thethiny', 'id': 6018214, 'node_id': 'MDQ6VXNlcjYwMTgyMTQ=', 'avatar_url': 'https://avatars.githubusercontent.com/u/6018214?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/thethiny', 'html_url': 'https://github.com/thethiny', 'followers_url': 'https://api.github.com/users/thethiny/followers', 'following_url': 'https://api.github.com/users/thethiny/following{/other_user}', 'gists_url': 'https://api.github.com/users/thethiny/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/thethiny/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/thethiny/subscriptions', 'organizations_url': 'https://api.github.com/users/thethiny/orgs', 'repos_url': 'https://api.github.com/users/thethiny/repos', 'events_url': 'https://api.github.com/users/thethiny/events{/privacy}', 'received_events_url': 'https://api.github.com/users/thethiny/received_events', 'type': 'User', 'user_view_type': 'public', 'site_admin': False}, 'created_at': '2026-07-17T21:03:14Z', 'updated_at': '2026-07-17T21:03:14Z', 'body': "> Happy to chip in if there's anything still outstanding\r\n\r\nI will push today's work in a bit to this branch but I'm doing some benchmarking first, and u can take a look if you're interested? I noticed difference in conversion speed between lossy and lossless wbfs and I think you might be able to have an opinion, but I need to confirm all benchmarks are accurate first to be able to produce a reproduceable report.", 'author_association': 'NONE', 'reactions': {'url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/comments/5007452123/reactions', 'total_count': 0, '+1': 0, '-1': 0, 'laugh': 0, 'hooray': 0, 'confused': 0, 'heart': 0, 'rocket': 0, 'eyes': 0}, 'performed_via_github_app': None, 'minimized': None}, 'repository': {'id': 11577304, 'node_id': 'MDEwOlJlcG9zaXRvcnkxMTU3NzMwNA==', 'name': 'dolphin', 'full_name': 'dolphin-emu/dolphin', 'private': False, 'owner': {'login': 'dolphin-emu', 'id': 5050316, 'node_id': 'MDEyOk9yZ2FuaXphdGlvbjUwNTAzMTY=', 'avatar_url': 'https://avatars.githubusercontent.com/u/5050316?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/dolphin-emu', 'html_url': 'https://github.com/dolphin-emu', 'followers_url': 'https://api.github.com/users/dolphin-emu/followers', 'following_url': 'https://api.github.com/users/dolphin-emu/following{/other_user}', 'gists_url': 'https://api.github.com/users/dolphin-emu/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/dolphin-emu/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/dolphin-emu/subscriptions', 'organizations_url': 'https://api.github.com/users/dolphin-emu/orgs', 'repos_url': 'https://api.github.com/users/dolphin-emu/repos', 'events_url': 'https://api.github.com/users/dolphin-emu/events{/privacy}', 'received_events_url': 'https://api.github.com/users/dolphin-emu/received_events', 'type': 'Organization', 'user_view_type': 'public', 'site_admin': False}, 'html_url': 'https://github.com/dolphin-emu/dolphin', 'description': 'Dolphin is a GameCube / Wii emulator, allowing you to play games for these two platforms on PC with improvements.', 'fork': False, 'url': 'https://api.github.com/repos/dolphin-emu/dolphin', 'forks_url': 'https://api.github.com/repos/dolphin-emu/dolphin/forks', 'keys_url': 'https://api.github.com/repos/dolphin-emu/dolphin/keys{/key_id}', 'collaborators_url': 'https://api.github.com/repos/dolphin-emu/dolphin/collaborators{/collaborator}', 'teams_url': 'https://api.github.com/repos/dolphin-emu/dolphin/teams', 'hooks_url': 'https://api.github.com/repos/dolphin-emu/dolphin/hooks', 'issue_events_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/events{/number}', 'events_url': 'https://api.github.com/repos/dolphin-emu/dolphin/events', 'assignees_url': 'https://api.github.com/repos/dolphin-emu/dolphin/assignees{/user}', 'branches_url': 'https://api.github.com/repos/dolphin-emu/dolphin/branches{/branch}', 'tags_url': 'https://api.github.com/repos/dolphin-emu/dolphin/tags', 'blobs_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/blobs{/sha}', 'git_tags_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/tags{/sha}', 'git_refs_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/refs{/sha}', 'trees_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/trees{/sha}', 'statuses_url': 'https://api.github.com/repos/dolphin-emu/dolphin/statuses/{sha}', 'languages_url': 'https://api.github.com/repos/dolphin-emu/dolphin/languages', 'stargazers_url': 'https://api.github.com/repos/dolphin-emu/dolphin/stargazers', 'contributors_url': 'https://api.github.com/repos/dolphin-emu/dolphin/contributors', 'subscribers_url': 'https://api.github.com/repos/dolphin-emu/dolphin/subscribers', 'subscription_url': 'https://api.github.com/repos/dolphin-emu/dolphin/subscription', 'commits_url': 'https://api.github.com/repos/dolphin-emu/dolphin/commits{/sha}', 'git_commits_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/commits{/sha}', 'comments_url': 'https://api.github.com/repos/dolphin-emu/dolphin/comments{/number}', 'issue_comment_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/comments{/number}', 'contents_url': 'https://api.github.com/repos/dolphin-emu/dolphin/contents/{+path}', 'compare_url': 'https://api.github.com/repos/dolphin-emu/dolphin/compare/{base}...{head}', 'merges_url': 'https://api.github.com/repos/dolphin-emu/dolphin/merges', 'archive_url': 'https://api.github.com/repos/dolphin-emu/dolphin/{archive_format}{/ref}', 'downloads_url': 'https://api.github.com/repos/dolphin-emu/dolphin/downloads', 'issues_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues{/number}', 'pulls_url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls{/number}', 'milestones_url': 'https://api.github.com/repos/dolphin-emu/dolphin/milestones{/number}', 'notifications_url': 'https://api.github.com/repos/dolphin-emu/dolphin/notifications{?since,all,participating}', 'labels_url': 'https://api.github.com/repos/dolphin-emu/dolphin/labels{/name}', 'releases_url': 'https://api.github.com/repos/dolphin-emu/dolphin/releases{/id}', 'deployments_url': 'https://api.github.com/repos/dolphin-emu/dolphin/deployments', 'created_at': '2013-07-22T09:07:57Z', 'updated_at': '2026-07-17T13:03:27Z', 'pushed_at': '2026-07-15T20:58:02Z', 'git_url': 'git://github.com/dolphin-emu/dolphin.git', 'ssh_url': 'git@github.com:dolphin-emu/dolphin.git', 'clone_url': 'https://github.com/dolphin-emu/dolphin.git', 'svn_url': 'https://github.com/dolphin-emu/dolphin', 'homepage': 'https://dolphin-emu.org', 'size': 558444, 'stargazers_count': 15268, 'watchers_count': 15268, 'language': 'C++', 'has_issues': False, 'has_projects': False, 'has_downloads': True, 'has_wiki': True, 'has_pages': False, 'has_discussions': False, 'forks_count': 3162, 'mirror_url': None, 'archived': False, 'disabled': False, 'open_issues_count': 447, 'license': {'key': 'other', 'name': 'Other', 'spdx_id': 'NOASSERTION', 'url': None, 'node_id': 'MDc6TGljZW5zZTA='}, 'allow_forking': True, 'is_template': False, 'web_commit_signoff_required': False, 'has_pull_requests': True, 'pull_request_creation_policy': 'all', 'topics': ['cpp', 'emulation', 'emulator', 'gamecube', 'wii'], 'visibility': 'public', 'forks': 3162, 'open_issues': 447, 'watchers': 15268, 'default_branch': 'master', 'custom_properties': {}}, 'organization': {'login': 'dolphin-emu', 'id': 5050316, 'node_id': 'MDEyOk9yZ2FuaXphdGlvbjUwNTAzMTY=', 'url': 'https://api.github.com/orgs/dolphin-emu', 'repos_url': 'https://api.github.com/orgs/dolphin-emu/repos', 'events_url': 'https://api.github.com/orgs/dolphin-emu/events', 'hooks_url': 'https://api.github.com/orgs/dolphin-emu/hooks', 'issues_url': 'https://api.github.com/orgs/dolphin-emu/issues', 'members_url': 'https://api.github.com/orgs/dolphin-emu/members{/member}', 'public_members_url': 'https://api.github.com/orgs/dolphin-emu/public_members{/member}', 'avatar_url': 'https://avatars.githubusercontent.com/u/5050316?v=4', 'description': ''}, 'sender': {'login': 'thethiny', 'id': 6018214, 'node_id': 'MDQ6VXNlcjYwMTgyMTQ=', 'avatar_url': 'https://avatars.githubusercontent.com/u/6018214?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/thethiny', 'html_url': 'https://github.com/thethiny', 'followers_url': 'https://api.github.com/users/thethiny/followers', 'following_url': 'https://api.github.com/users/thethiny/following{/other_user}', 'gists_url': 'https://api.github.com/users/thethiny/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/thethiny/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/thethiny/subscriptions', 'organizations_url': 'https://api.github.com/users/thethiny/orgs', 'repos_url': 'https://api.github.com/users/thethiny/repos', 'events_url': 'https://api.github.com/users/thethiny/events{/privacy}', 'received_events_url': 'https://api.github.com/users/thethiny/received_events', 'type': 'User', 'user_view_type': 'public', 'site_admin': False}, 'installation': {'id': 35437981, 'node_id': 'MDIzOkludGVncmF0aW9uSW5zdGFsbGF0aW9uMzU0Mzc5ODE='}}, 'type': 'gh_issue_comment'}
2026-07-17T20:09:45.630615	{'source': 'ghhookparser', 'repo': 'dolphin-emu/dolphin', 'author': 'Nanook', 'action': 'created', 'id': 14731, 'title': 'Convert To WBFS Support', 'url': 'https://github.com/dolphin-emu/dolphin/pull/14731#issuecomment-5007081539', 'safe_author': False, 'body': "Happy to chip in if there's anything still outstanding", 'raw': {'action': 'created', 'issue': {'url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/14731', 'repository_url': 'https://api.github.com/repos/dolphin-emu/dolphin', 'labels_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/14731/labels{/name}', 'comments_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/14731/comments', 'events_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/14731/events', 'html_url': 'https://github.com/dolphin-emu/dolphin/pull/14731', 'id': 4888393904, 'node_id': 'PR_kwDOALCn2M7x0I-2', 'number': 14731, 'title': 'Convert To WBFS Support', 'user': {'login': 'thethiny', 'id': 6018214, 'node_id': 'MDQ6VXNlcjYwMTgyMTQ=', 'avatar_url': 'https://avatars.githubusercontent.com/u/6018214?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/thethiny', 'html_url': 'https://github.com/thethiny', 'followers_url': 'https://api.github.com/users/thethiny/followers', 'following_url': 'https://api.github.com/users/thethiny/following{/other_user}', 'gists_url': 'https://api.github.com/users/thethiny/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/thethiny/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/thethiny/subscriptions', 'organizations_url': 'https://api.github.com/users/thethiny/orgs', 'repos_url': 'https://api.github.com/users/thethiny/repos', 'events_url': 'https://api.github.com/users/thethiny/events{/privacy}', 'received_events_url': 'https://api.github.com/users/thethiny/received_events', 'type': 'User', 'user_view_type': 'public', 'site_admin': False}, 'labels': [], 'state': 'open', 'locked': False, 'assignees': [], 'milestone': None, 'comments': 30, 'created_at': '2026-07-15T01:16:25Z', 'updated_at': '2026-07-17T20:09:44Z', 'closed_at': None, 'assignee': None, 'author_association': 'NONE', 'issue_field_values': [], 'type': None, 'active_lock_reason': None, 'draft': False, 'pull_request': {'url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/14731', 'html_url': 'https://github.com/dolphin-emu/dolphin/pull/14731', 'diff_url': 'https://github.com/dolphin-emu/dolphin/pull/14731.diff', 'patch_url': 'https://github.com/dolphin-emu/dolphin/pull/14731.patch', 'merged_at': None}, 'body': "This PR introduces Conversion **to** WBFS support. WBFS is the format that is used by USB Loaders on a real Wii device.\r\n\r\n## Design decisions & hardcoded values\r\nThe writer uses fixed sector sizes that match what [libwbfs (the reference implementation by kwiirk)](https://github.com/kwiirk/wbfs/blob/master/libwbfs/libwbfs.c#L128-L134) computes for a standard single-layer Wii disc. These 2 hardcodes are stable and work correctly across all my testings.\r\n- HD sector shift: 9 (512 bytes)\r\n- WBFS sector shift: 21 (2 MiB)\r\nThese are not configurable via the UI. All existing WBFS tools use these values, and since the aim is to support USB Loaders then this has been tested and it is working on a real Wii.\r\n\r\nConverting from WBFS is not enabled. The existing `WbfsFileReader` reports `DataSizeType::UpperBound`, and `ShouldAllowConversion()` requires `Accurate`. I am able to support this but since it was hardcoded by the Dolphin team I thought a discussion is warranted.\r\n\r\n## Testing\r\n- Verified with DolphinTool header and DolphinTool verify\r\n- Verified with wit FILETYPE and wit DUMP (Wiimm's ISO Tools recognizes valid WBFS structure, partitions, encryption)\r\n- Tested ISO to WBFS and RVZ to WBFS conversions\r\n- Output file sizes match Wii Backup Manager when scrubbing is enabled (~0.1% difference), works when scrubbing is disabled.\r\n- Output WBFS files play correctly in Dolphin\r\n- Output WBFS files play correctly on a real Wii using USB Loader GX e25c4f3\r\n", 'reactions': {'url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/14731/reactions', 'total_count': 2, '+1': 2, '-1': 0, 'laugh': 0, 'hooray': 0, 'confused': 0, 'heart': 0, 'rocket': 0, 'eyes': 0}, 'timeline_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/14731/timeline', 'performed_via_github_app': None, 'state_reason': None}, 'comment': {'url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/comments/5007081539', 'html_url': 'https://github.com/dolphin-emu/dolphin/pull/14731#issuecomment-5007081539', 'issue_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/14731', 'id': 5007081539, 'node_id': 'IC_kwDOALCn2M8AAAABKnIAQw', 'user': {'login': 'Nanook', 'id': 188841, 'node_id': 'MDQ6VXNlcjE4ODg0MQ==', 'avatar_url': 'https://avatars.githubusercontent.com/u/188841?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/Nanook', 'html_url': 'https://github.com/Nanook', 'followers_url': 'https://api.github.com/users/Nanook/followers', 'following_url': 'https://api.github.com/users/Nanook/following{/other_user}', 'gists_url': 'https://api.github.com/users/Nanook/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/Nanook/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/Nanook/subscriptions', 'organizations_url': 'https://api.github.com/users/Nanook/orgs', 'repos_url': 'https://api.github.com/users/Nanook/repos', 'events_url': 'https://api.github.com/users/Nanook/events{/privacy}', 'received_events_url': 'https://api.github.com/users/Nanook/received_events', 'type': 'User', 'user_view_type': 'public', 'site_admin': False}, 'created_at': '2026-07-17T20:09:44Z', 'updated_at': '2026-07-17T20:09:44Z', 'body': "Happy to chip in if there's anything still outstanding", 'author_association': 'NONE', 'reactions': {'url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/comments/5007081539/reactions', 'total_count': 0, '+1': 0, '-1': 0, 'laugh': 0, 'hooray': 0, 'confused': 0, 'heart': 0, 'rocket': 0, 'eyes': 0}, 'performed_via_github_app': None, 'minimized': None}, 'repository': {'id': 11577304, 'node_id': 'MDEwOlJlcG9zaXRvcnkxMTU3NzMwNA==', 'name': 'dolphin', 'full_name': 'dolphin-emu/dolphin', 'private': False, 'owner': {'login': 'dolphin-emu', 'id': 5050316, 'node_id': 'MDEyOk9yZ2FuaXphdGlvbjUwNTAzMTY=', 'avatar_url': 'https://avatars.githubusercontent.com/u/5050316?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/dolphin-emu', 'html_url': 'https://github.com/dolphin-emu', 'followers_url': 'https://api.github.com/users/dolphin-emu/followers', 'following_url': 'https://api.github.com/users/dolphin-emu/following{/other_user}', 'gists_url': 'https://api.github.com/users/dolphin-emu/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/dolphin-emu/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/dolphin-emu/subscriptions', 'organizations_url': 'https://api.github.com/users/dolphin-emu/orgs', 'repos_url': 'https://api.github.com/users/dolphin-emu/repos', 'events_url': 'https://api.github.com/users/dolphin-emu/events{/privacy}', 'received_events_url': 'https://api.github.com/users/dolphin-emu/received_events', 'type': 'Organization', 'user_view_type': 'public', 'site_admin': False}, 'html_url': 'https://github.com/dolphin-emu/dolphin', 'description': 'Dolphin is a GameCube / Wii emulator, allowing you to play games for these two platforms on PC with improvements.', 'fork': False, 'url': 'https://api.github.com/repos/dolphin-emu/dolphin', 'forks_url': 'https://api.github.com/repos/dolphin-emu/dolphin/forks', 'keys_url': 'https://api.github.com/repos/dolphin-emu/dolphin/keys{/key_id}', 'collaborators_url': 'https://api.github.com/repos/dolphin-emu/dolphin/collaborators{/collaborator}', 'teams_url': 'https://api.github.com/repos/dolphin-emu/dolphin/teams', 'hooks_url': 'https://api.github.com/repos/dolphin-emu/dolphin/hooks', 'issue_events_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/events{/number}', 'events_url': 'https://api.github.com/repos/dolphin-emu/dolphin/events', 'assignees_url': 'https://api.github.com/repos/dolphin-emu/dolphin/assignees{/user}', 'branches_url': 'https://api.github.com/repos/dolphin-emu/dolphin/branches{/branch}', 'tags_url': 'https://api.github.com/repos/dolphin-emu/dolphin/tags', 'blobs_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/blobs{/sha}', 'git_tags_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/tags{/sha}', 'git_refs_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/refs{/sha}', 'trees_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/trees{/sha}', 'statuses_url': 'https://api.github.com/repos/dolphin-emu/dolphin/statuses/{sha}', 'languages_url': 'https://api.github.com/repos/dolphin-emu/dolphin/languages', 'stargazers_url': 'https://api.github.com/repos/dolphin-emu/dolphin/stargazers', 'contributors_url': 'https://api.github.com/repos/dolphin-emu/dolphin/contributors', 'subscribers_url': 'https://api.github.com/repos/dolphin-emu/dolphin/subscribers', 'subscription_url': 'https://api.github.com/repos/dolphin-emu/dolphin/subscription', 'commits_url': 'https://api.github.com/repos/dolphin-emu/dolphin/commits{/sha}', 'git_commits_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/commits{/sha}', 'comments_url': 'https://api.github.com/repos/dolphin-emu/dolphin/comments{/number}', 'issue_comment_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/comments{/number}', 'contents_url': 'https://api.github.com/repos/dolphin-emu/dolphin/contents/{+path}', 'compare_url': 'https://api.github.com/repos/dolphin-emu/dolphin/compare/{base}...{head}', 'merges_url': 'https://api.github.com/repos/dolphin-emu/dolphin/merges', 'archive_url': 'https://api.github.com/repos/dolphin-emu/dolphin/{archive_format}{/ref}', 'downloads_url': 'https://api.github.com/repos/dolphin-emu/dolphin/downloads', 'issues_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues{/number}', 'pulls_url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls{/number}', 'milestones_url': 'https://api.github.com/repos/dolphin-emu/dolphin/milestones{/number}', 'notifications_url': 'https://api.github.com/repos/dolphin-emu/dolphin/notifications{?since,all,participating}', 'labels_url': 'https://api.github.com/repos/dolphin-emu/dolphin/labels{/name}', 'releases_url': 'https://api.github.com/repos/dolphin-emu/dolphin/releases{/id}', 'deployments_url': 'https://api.github.com/repos/dolphin-emu/dolphin/deployments', 'created_at': '2013-07-22T09:07:57Z', 'updated_at': '2026-07-17T13:03:27Z', 'pushed_at': '2026-07-15T20:58:02Z', 'git_url': 'git://github.com/dolphin-emu/dolphin.git', 'ssh_url': 'git@github.com:dolphin-emu/dolphin.git', 'clone_url': 'https://github.com/dolphin-emu/dolphin.git', 'svn_url': 'https://github.com/dolphin-emu/dolphin', 'homepage': 'https://dolphin-emu.org', 'size': 558444, 'stargazers_count': 15268, 'watchers_count': 15268, 'language': 'C++', 'has_issues': False, 'has_projects': False, 'has_downloads': True, 'has_wiki': True, 'has_pages': False, 'has_discussions': False, 'forks_count': 3162, 'mirror_url': None, 'archived': False, 'disabled': False, 'open_issues_count': 447, 'license': {'key': 'other', 'name': 'Other', 'spdx_id': 'NOASSERTION', 'url': None, 'node_id': 'MDc6TGljZW5zZTA='}, 'allow_forking': True, 'is_template': False, 'web_commit_signoff_required': False, 'has_pull_requests': True, 'pull_request_creation_policy': 'all', 'topics': ['cpp', 'emulation', 'emulator', 'gamecube', 'wii'], 'visibility': 'public', 'forks': 3162, 'open_issues': 447, 'watchers': 15268, 'default_branch': 'master', 'custom_properties': {}}, 'organization': {'login': 'dolphin-emu', 'id': 5050316, 'node_id': 'MDEyOk9yZ2FuaXphdGlvbjUwNTAzMTY=', 'url': 'https://api.github.com/orgs/dolphin-emu', 'repos_url': 'https://api.github.com/orgs/dolphin-emu/repos', 'events_url': 'https://api.github.com/orgs/dolphin-emu/events', 'hooks_url': 'https://api.github.com/orgs/dolphin-emu/hooks', 'issues_url': 'https://api.github.com/orgs/dolphin-emu/issues', 'members_url': 'https://api.github.com/orgs/dolphin-emu/members{/member}', 'public_members_url': 'https://api.github.com/orgs/dolphin-emu/public_members{/member}', 'avatar_url': 'https://avatars.githubusercontent.com/u/5050316?v=4', 'description': ''}, 'sender': {'login': 'Nanook', 'id': 188841, 'node_id': 'MDQ6VXNlcjE4ODg0MQ==', 'avatar_url': 'https://avatars.githubusercontent.com/u/188841?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/Nanook', 'html_url': 'https://github.com/Nanook', 'followers_url': 'https://api.github.com/users/Nanook/followers', 'following_url': 'https://api.github.com/users/Nanook/following{/other_user}', 'gists_url': 'https://api.github.com/users/Nanook/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/Nanook/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/Nanook/subscriptions', 'organizations_url': 'https://api.github.com/users/Nanook/orgs', 'repos_url': 'https://api.github.com/users/Nanook/repos', 'events_url': 'https://api.github.com/users/Nanook/events{/privacy}', 'received_events_url': 'https://api.github.com/users/Nanook/received_events', 'type': 'User', 'user_view_type': 'public', 'site_admin': False}, 'installation': {'id': 35437981, 'node_id': 'MDIzOkludGVncmF0aW9uSW5zdGFsbGF0aW9uMzU0Mzc5ODE='}}, 'type': 'gh_issue_comment'}
2026-07-17T17:09:50.874373	{'source': 'ghhookparser', 'repo': 'dolphin-emu/dolphin', 'author': 'JosJuice', 'action': 'created', 'id': 14736, 'title': 'Auto assign wii controllers in netplay', 'url': 'https://github.com/dolphin-emu/dolphin/pull/14736#issuecomment-5005642992', 'safe_author': True, 'body': "I don't think it would be so bad. The only problem it should cause is the same mapping confusion that you'll get if you're playing locally.\r\n\r\nNote that when the previous pull request was made in 2020, Wii Remotes were far worse at syncing over netplay. I would say that that problem isn't there anymore.", 'raw': {'action': 'created', 'issue': {'url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/14736', 'repository_url': 'https://api.github.com/repos/dolphin-emu/dolphin', 'labels_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/14736/labels{/name}', 'comments_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/14736/comments', 'events_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/14736/events', 'html_url': 'https://github.com/dolphin-emu/dolphin/pull/14736', 'id': 4911128480, 'node_id': 'PR_kwDOALCn2M7y96iL', 'number': 14736, 'title': 'Auto assign wii controllers in netplay', 'user': {'login': 'tom-pratt', 'id': 10612949, 'node_id': 'MDQ6VXNlcjEwNjEyOTQ5', 'avatar_url': 'https://avatars.githubusercontent.com/u/10612949?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/tom-pratt', 'html_url': 'https://github.com/tom-pratt', 'followers_url': 'https://api.github.com/users/tom-pratt/followers', 'following_url': 'https://api.github.com/users/tom-pratt/following{/other_user}', 'gists_url': 'https://api.github.com/users/tom-pratt/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/tom-pratt/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/tom-pratt/subscriptions', 'organizations_url': 'https://api.github.com/users/tom-pratt/orgs', 'repos_url': 'https://api.github.com/users/tom-pratt/repos', 'events_url': 'https://api.github.com/users/tom-pratt/events{/privacy}', 'received_events_url': 'https://api.github.com/users/tom-pratt/received_events', 'type': 'User', 'user_view_type': 'public', 'site_admin': False}, 'labels': [], 'state': 'open', 'locked': False, 'assignees': [], 'milestone': None, 'comments': 2, 'created_at': '2026-07-17T12:04:49Z', 'updated_at': '2026-07-17T17:09:48Z', 'closed_at': None, 'assignee': None, 'author_association': 'CONTRIBUTOR', 'issue_field_values': [], 'type': None, 'active_lock_reason': None, 'draft': False, 'pull_request': {'url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/14736', 'html_url': 'https://github.com/dolphin-emu/dolphin/pull/14736', 'diff_url': 'https://github.com/dolphin-emu/dolphin/pull/14736.diff', 'patch_url': 'https://github.com/dolphin-emu/dolphin/pull/14736.patch', 'merged_at': None}, 'body': 'Just copy the gamecube logic and automatically assign players to the first empty slot.\r\n\r\nMore consistent with GameCube and helps Android hosts where there is no UI for managing controller mappings currently.', 'reactions': {'url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/14736/reactions', 'total_count': 0, '+1': 0, '-1': 0, 'laugh': 0, 'hooray': 0, 'confused': 0, 'heart': 0, 'rocket': 0, 'eyes': 0}, 'timeline_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/14736/timeline', 'performed_via_github_app': None, 'state_reason': None}, 'comment': {'url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/comments/5005642992', 'html_url': 'https://github.com/dolphin-emu/dolphin/pull/14736#issuecomment-5005642992', 'issue_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/14736', 'id': 5005642992, 'node_id': 'IC_kwDOALCn2M8AAAABKlwM8A', 'user': {'login': 'JosJuice', 'id': 6716818, 'node_id': 'MDQ6VXNlcjY3MTY4MTg=', 'avatar_url': 'https://avatars.githubusercontent.com/u/6716818?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/JosJuice', 'html_url': 'https://github.com/JosJuice', 'followers_url': 'https://api.github.com/users/JosJuice/followers', 'following_url': 'https://api.github.com/users/JosJuice/following{/other_user}', 'gists_url': 'https://api.github.com/users/JosJuice/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/JosJuice/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/JosJuice/subscriptions', 'organizations_url': 'https://api.github.com/users/JosJuice/orgs', 'repos_url': 'https://api.github.com/users/JosJuice/repos', 'events_url': 'https://api.github.com/users/JosJuice/events{/privacy}', 'received_events_url': 'https://api.github.com/users/JosJuice/received_events', 'type': 'User', 'user_view_type': 'public', 'site_admin': False}, 'created_at': '2026-07-17T17:09:48Z', 'updated_at': '2026-07-17T17:09:48Z', 'body': "I don't think it would be so bad. The only problem it should cause is the same mapping confusion that you'll get if you're playing locally.\r\n\r\nNote that when the previous pull request was made in 2020, Wii Remotes were far worse at syncing over netplay. I would say that that problem isn't there anymore.", 'author_association': 'MEMBER', 'reactions': {'url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/comments/5005642992/reactions', 'total_count': 0, '+1': 0, '-1': 0, 'laugh': 0, 'hooray': 0, 'confused': 0, 'heart': 0, 'rocket': 0, 'eyes': 0}, 'performed_via_github_app': None, 'minimized': None}, 'repository': {'id': 11577304, 'node_id': 'MDEwOlJlcG9zaXRvcnkxMTU3NzMwNA==', 'name': 'dolphin', 'full_name': 'dolphin-emu/dolphin', 'private': False, 'owner': {'login': 'dolphin-emu', 'id': 5050316, 'node_id': 'MDEyOk9yZ2FuaXphdGlvbjUwNTAzMTY=', 'avatar_url': 'https://avatars.githubusercontent.com/u/5050316?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/dolphin-emu', 'html_url': 'https://github.com/dolphin-emu', 'followers_url': 'https://api.github.com/users/dolphin-emu/followers', 'following_url': 'https://api.github.com/users/dolphin-emu/following{/other_user}', 'gists_url': 'https://api.github.com/users/dolphin-emu/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/dolphin-emu/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/dolphin-emu/subscriptions', 'organizations_url': 'https://api.github.com/users/dolphin-emu/orgs', 'repos_url': 'https://api.github.com/users/dolphin-emu/repos', 'events_url': 'https://api.github.com/users/dolphin-emu/events{/privacy}', 'received_events_url': 'https://api.github.com/users/dolphin-emu/received_events', 'type': 'Organization', 'user_view_type': 'public', 'site_admin': False}, 'html_url': 'https://github.com/dolphin-emu/dolphin', 'description': 'Dolphin is a GameCube / Wii emulator, allowing you to play games for these two platforms on PC with improvements.', 'fork': False, 'url': 'https://api.github.com/repos/dolphin-emu/dolphin', 'forks_url': 'https://api.github.com/repos/dolphin-emu/dolphin/forks', 'keys_url': 'https://api.github.com/repos/dolphin-emu/dolphin/keys{/key_id}', 'collaborators_url': 'https://api.github.com/repos/dolphin-emu/dolphin/collaborators{/collaborator}', 'teams_url': 'https://api.github.com/repos/dolphin-emu/dolphin/teams', 'hooks_url': 'https://api.github.com/repos/dolphin-emu/dolphin/hooks', 'issue_events_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/events{/number}', 'events_url': 'https://api.github.com/repos/dolphin-emu/dolphin/events', 'assignees_url': 'https://api.github.com/repos/dolphin-emu/dolphin/assignees{/user}', 'branches_url': 'https://api.github.com/repos/dolphin-emu/dolphin/branches{/branch}', 'tags_url': 'https://api.github.com/repos/dolphin-emu/dolphin/tags', 'blobs_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/blobs{/sha}', 'git_tags_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/tags{/sha}', 'git_refs_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/refs{/sha}', 'trees_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/trees{/sha}', 'statuses_url': 'https://api.github.com/repos/dolphin-emu/dolphin/statuses/{sha}', 'languages_url': 'https://api.github.com/repos/dolphin-emu/dolphin/languages', 'stargazers_url': 'https://api.github.com/repos/dolphin-emu/dolphin/stargazers', 'contributors_url': 'https://api.github.com/repos/dolphin-emu/dolphin/contributors', 'subscribers_url': 'https://api.github.com/repos/dolphin-emu/dolphin/subscribers', 'subscription_url': 'https://api.github.com/repos/dolphin-emu/dolphin/subscription', 'commits_url': 'https://api.github.com/repos/dolphin-emu/dolphin/commits{/sha}', 'git_commits_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/commits{/sha}', 'comments_url': 'https://api.github.com/repos/dolphin-emu/dolphin/comments{/number}', 'issue_comment_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/comments{/number}', 'contents_url': 'https://api.github.com/repos/dolphin-emu/dolphin/contents/{+path}', 'compare_url': 'https://api.github.com/repos/dolphin-emu/dolphin/compare/{base}...{head}', 'merges_url': 'https://api.github.com/repos/dolphin-emu/dolphin/merges', 'archive_url': 'https://api.github.com/repos/dolphin-emu/dolphin/{archive_format}{/ref}', 'downloads_url': 'https://api.github.com/repos/dolphin-emu/dolphin/downloads', 'issues_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues{/number}', 'pulls_url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls{/number}', 'milestones_url': 'https://api.github.com/repos/dolphin-emu/dolphin/milestones{/number}', 'notifications_url': 'https://api.github.com/repos/dolphin-emu/dolphin/notifications{?since,all,participating}', 'labels_url': 'https://api.github.com/repos/dolphin-emu/dolphin/labels{/name}', 'releases_url': 'https://api.github.com/repos/dolphin-emu/dolphin/releases{/id}', 'deployments_url': 'https://api.github.com/repos/dolphin-emu/dolphin/deployments', 'created_at': '2013-07-22T09:07:57Z', 'updated_at': '2026-07-17T13:03:27Z', 'pushed_at': '2026-07-15T20:58:02Z', 'git_url': 'git://github.com/dolphin-emu/dolphin.git', 'ssh_url': 'git@github.com:dolphin-emu/dolphin.git', 'clone_url': 'https://github.com/dolphin-emu/dolphin.git', 'svn_url': 'https://github.com/dolphin-emu/dolphin', 'homepage': 'https://dolphin-emu.org', 'size': 558444, 'stargazers_count': 15268, 'watchers_count': 15268, 'language': 'C++', 'has_issues': False, 'has_projects': False, 'has_downloads': True, 'has_wiki': True, 'has_pages': False, 'has_discussions': False, 'forks_count': 3162, 'mirror_url': None, 'archived': False, 'disabled': False, 'open_issues_count': 447, 'license': {'key': 'other', 'name': 'Other', 'spdx_id': 'NOASSERTION', 'url': None, 'node_id': 'MDc6TGljZW5zZTA='}, 'allow_forking': True, 'is_template': False, 'web_commit_signoff_required': False, 'has_pull_requests': True, 'pull_request_creation_policy': 'all', 'topics': ['cpp', 'emulation', 'emulator', 'gamecube', 'wii'], 'visibility': 'public', 'forks': 3162, 'open_issues': 447, 'watchers': 15268, 'default_branch': 'master', 'custom_properties': {}}, 'organization': {'login': 'dolphin-emu', 'id': 5050316, 'node_id': 'MDEyOk9yZ2FuaXphdGlvbjUwNTAzMTY=', 'url': 'https://api.github.com/orgs/dolphin-emu', 'repos_url': 'https://api.github.com/orgs/dolphin-emu/repos', 'events_url': 'https://api.github.com/orgs/dolphin-emu/events', 'hooks_url': 'https://api.github.com/orgs/dolphin-emu/hooks', 'issues_url': 'https://api.github.com/orgs/dolphin-emu/issues', 'members_url': 'https://api.github.com/orgs/dolphin-emu/members{/member}', 'public_members_url': 'https://api.github.com/orgs/dolphin-emu/public_members{/member}', 'avatar_url': 'https://avatars.githubusercontent.com/u/5050316?v=4', 'description': ''}, 'sender': {'login': 'JosJuice', 'id': 6716818, 'node_id': 'MDQ6VXNlcjY3MTY4MTg=', 'avatar_url': 'https://avatars.githubusercontent.com/u/6716818?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/JosJuice', 'html_url': 'https://github.com/JosJuice', 'followers_url': 'https://api.github.com/users/JosJuice/followers', 'following_url': 'https://api.github.com/users/JosJuice/following{/other_user}', 'gists_url': 'https://api.github.com/users/JosJuice/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/JosJuice/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/JosJuice/subscriptions', 'organizations_url': 'https://api.github.com/users/JosJuice/orgs', 'repos_url': 'https://api.github.com/users/JosJuice/repos', 'events_url': 'https://api.github.com/users/JosJuice/events{/privacy}', 'received_events_url': 'https://api.github.com/users/JosJuice/received_events', 'type': 'User', 'user_view_type': 'public', 'site_admin': False}, 'installation': {'id': 35437981, 'node_id': 'MDIzOkludGVncmF0aW9uSW5zdGFsbGF0aW9uMzU0Mzc5ODE='}}, 'type': 'gh_issue_comment'}
2026-07-17T17:05:11.977359	{'source': 'ghhookparser', 'repo': 'dolphin-emu/dolphin', 'author': 'JosJuice', 'action': 'created', 'id': 14735, 'title': 'Android: Dual core warning when hosting netplay', 'url': 'https://github.com/dolphin-emu/dolphin/pull/14735#issuecomment-5005606644', 'safe_author': True, 'body': 'We should also mention that it makes some games not work at all. (They get stuck on a black screen.)', 'raw': {'action': 'created', 'issue': {'url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/14735', 'repository_url': 'https://api.github.com/repos/dolphin-emu/dolphin', 'labels_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/14735/labels{/name}', 'comments_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/14735/comments', 'events_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/14735/events', 'html_url': 'https://github.com/dolphin-emu/dolphin/pull/14735', 'id': 4910915492, 'node_id': 'PR_kwDOALCn2M7y9ONM', 'number': 14735, 'title': 'Android: Dual core warning when hosting netplay', 'user': {'login': 'tom-pratt', 'id': 10612949, 'node_id': 'MDQ6VXNlcjEwNjEyOTQ5', 'avatar_url': 'https://avatars.githubusercontent.com/u/10612949?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/tom-pratt', 'html_url': 'https://github.com/tom-pratt', 'followers_url': 'https://api.github.com/users/tom-pratt/followers', 'following_url': 'https://api.github.com/users/tom-pratt/following{/other_user}', 'gists_url': 'https://api.github.com/users/tom-pratt/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/tom-pratt/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/tom-pratt/subscriptions', 'organizations_url': 'https://api.github.com/users/tom-pratt/orgs', 'repos_url': 'https://api.github.com/users/tom-pratt/repos', 'events_url': 'https://api.github.com/users/tom-pratt/events{/privacy}', 'received_events_url': 'https://api.github.com/users/tom-pratt/received_events', 'type': 'User', 'user_view_type': 'public', 'site_admin': False}, 'labels': [], 'state': 'open', 'locked': False, 'assignees': [], 'milestone': None, 'comments': 1, 'created_at': '2026-07-17T11:34:44Z', 'updated_at': '2026-07-17T17:05:10Z', 'closed_at': None, 'assignee': None, 'author_association': 'CONTRIBUTOR', 'issue_field_values': [], 'type': None, 'active_lock_reason': None, 'draft': False, 'pull_request': {'url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/14735', 'html_url': 'https://github.com/dolphin-emu/dolphin/pull/14735', 'diff_url': 'https://github.com/dolphin-emu/dolphin/pull/14735.diff', 'patch_url': 'https://github.com/dolphin-emu/dolphin/pull/14735.patch', 'merged_at': None}, 'body': 'Using dual core during netplay seems sufficiently detrimental that its worth showing this warning message and the option to turn dual core off when starting netplay.\r\n\r\n<img width="960" height="540" alt="Screenshot_20260717_133200" src="https://github.com/user-attachments/assets/ee1cc7d6-8868-41e1-af95-44b72c3fa6b4" />\r\n', 'reactions': {'url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/14735/reactions', 'total_count': 0, '+1': 0, '-1': 0, 'laugh': 0, 'hooray': 0, 'confused': 0, 'heart': 0, 'rocket': 0, 'eyes': 0}, 'timeline_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/14735/timeline', 'performed_via_github_app': None, 'state_reason': None}, 'comment': {'url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/comments/5005606644', 'html_url': 'https://github.com/dolphin-emu/dolphin/pull/14735#issuecomment-5005606644', 'issue_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/14735', 'id': 5005606644, 'node_id': 'IC_kwDOALCn2M8AAAABKlt-9A', 'user': {'login': 'JosJuice', 'id': 6716818, 'node_id': 'MDQ6VXNlcjY3MTY4MTg=', 'avatar_url': 'https://avatars.githubusercontent.com/u/6716818?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/JosJuice', 'html_url': 'https://github.com/JosJuice', 'followers_url': 'https://api.github.com/users/JosJuice/followers', 'following_url': 'https://api.github.com/users/JosJuice/following{/other_user}', 'gists_url': 'https://api.github.com/users/JosJuice/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/JosJuice/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/JosJuice/subscriptions', 'organizations_url': 'https://api.github.com/users/JosJuice/orgs', 'repos_url': 'https://api.github.com/users/JosJuice/repos', 'events_url': 'https://api.github.com/users/JosJuice/events{/privacy}', 'received_events_url': 'https://api.github.com/users/JosJuice/received_events', 'type': 'User', 'user_view_type': 'public', 'site_admin': False}, 'created_at': '2026-07-17T17:05:10Z', 'updated_at': '2026-07-17T17:05:10Z', 'body': 'We should also mention that it makes some games not work at all. (They get stuck on a black screen.)', 'author_association': 'MEMBER', 'reactions': {'url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/comments/5005606644/reactions', 'total_count': 0, '+1': 0, '-1': 0, 'laugh': 0, 'hooray': 0, 'confused': 0, 'heart': 0, 'rocket': 0, 'eyes': 0}, 'performed_via_github_app': None, 'minimized': None}, 'repository': {'id': 11577304, 'node_id': 'MDEwOlJlcG9zaXRvcnkxMTU3NzMwNA==', 'name': 'dolphin', 'full_name': 'dolphin-emu/dolphin', 'private': False, 'owner': {'login': 'dolphin-emu', 'id': 5050316, 'node_id': 'MDEyOk9yZ2FuaXphdGlvbjUwNTAzMTY=', 'avatar_url': 'https://avatars.githubusercontent.com/u/5050316?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/dolphin-emu', 'html_url': 'https://github.com/dolphin-emu', 'followers_url': 'https://api.github.com/users/dolphin-emu/followers', 'following_url': 'https://api.github.com/users/dolphin-emu/following{/other_user}', 'gists_url': 'https://api.github.com/users/dolphin-emu/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/dolphin-emu/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/dolphin-emu/subscriptions', 'organizations_url': 'https://api.github.com/users/dolphin-emu/orgs', 'repos_url': 'https://api.github.com/users/dolphin-emu/repos', 'events_url': 'https://api.github.com/users/dolphin-emu/events{/privacy}', 'received_events_url': 'https://api.github.com/users/dolphin-emu/received_events', 'type': 'Organization', 'user_view_type': 'public', 'site_admin': False}, 'html_url': 'https://github.com/dolphin-emu/dolphin', 'description': 'Dolphin is a GameCube / Wii emulator, allowing you to play games for these two platforms on PC with improvements.', 'fork': False, 'url': 'https://api.github.com/repos/dolphin-emu/dolphin', 'forks_url': 'https://api.github.com/repos/dolphin-emu/dolphin/forks', 'keys_url': 'https://api.github.com/repos/dolphin-emu/dolphin/keys{/key_id}', 'collaborators_url': 'https://api.github.com/repos/dolphin-emu/dolphin/collaborators{/collaborator}', 'teams_url': 'https://api.github.com/repos/dolphin-emu/dolphin/teams', 'hooks_url': 'https://api.github.com/repos/dolphin-emu/dolphin/hooks', 'issue_events_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/events{/number}', 'events_url': 'https://api.github.com/repos/dolphin-emu/dolphin/events', 'assignees_url': 'https://api.github.com/repos/dolphin-emu/dolphin/assignees{/user}', 'branches_url': 'https://api.github.com/repos/dolphin-emu/dolphin/branches{/branch}', 'tags_url': 'https://api.github.com/repos/dolphin-emu/dolphin/tags', 'blobs_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/blobs{/sha}', 'git_tags_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/tags{/sha}', 'git_refs_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/refs{/sha}', 'trees_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/trees{/sha}', 'statuses_url': 'https://api.github.com/repos/dolphin-emu/dolphin/statuses/{sha}', 'languages_url': 'https://api.github.com/repos/dolphin-emu/dolphin/languages', 'stargazers_url': 'https://api.github.com/repos/dolphin-emu/dolphin/stargazers', 'contributors_url': 'https://api.github.com/repos/dolphin-emu/dolphin/contributors', 'subscribers_url': 'https://api.github.com/repos/dolphin-emu/dolphin/subscribers', 'subscription_url': 'https://api.github.com/repos/dolphin-emu/dolphin/subscription', 'commits_url': 'https://api.github.com/repos/dolphin-emu/dolphin/commits{/sha}', 'git_commits_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/commits{/sha}', 'comments_url': 'https://api.github.com/repos/dolphin-emu/dolphin/comments{/number}', 'issue_comment_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/comments{/number}', 'contents_url': 'https://api.github.com/repos/dolphin-emu/dolphin/contents/{+path}', 'compare_url': 'https://api.github.com/repos/dolphin-emu/dolphin/compare/{base}...{head}', 'merges_url': 'https://api.github.com/repos/dolphin-emu/dolphin/merges', 'archive_url': 'https://api.github.com/repos/dolphin-emu/dolphin/{archive_format}{/ref}', 'downloads_url': 'https://api.github.com/repos/dolphin-emu/dolphin/downloads', 'issues_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues{/number}', 'pulls_url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls{/number}', 'milestones_url': 'https://api.github.com/repos/dolphin-emu/dolphin/milestones{/number}', 'notifications_url': 'https://api.github.com/repos/dolphin-emu/dolphin/notifications{?since,all,participating}', 'labels_url': 'https://api.github.com/repos/dolphin-emu/dolphin/labels{/name}', 'releases_url': 'https://api.github.com/repos/dolphin-emu/dolphin/releases{/id}', 'deployments_url': 'https://api.github.com/repos/dolphin-emu/dolphin/deployments', 'created_at': '2013-07-22T09:07:57Z', 'updated_at': '2026-07-17T13:03:27Z', 'pushed_at': '2026-07-15T20:58:02Z', 'git_url': 'git://github.com/dolphin-emu/dolphin.git', 'ssh_url': 'git@github.com:dolphin-emu/dolphin.git', 'clone_url': 'https://github.com/dolphin-emu/dolphin.git', 'svn_url': 'https://github.com/dolphin-emu/dolphin', 'homepage': 'https://dolphin-emu.org', 'size': 558444, 'stargazers_count': 15268, 'watchers_count': 15268, 'language': 'C++', 'has_issues': False, 'has_projects': False, 'has_downloads': True, 'has_wiki': True, 'has_pages': False, 'has_discussions': False, 'forks_count': 3162, 'mirror_url': None, 'archived': False, 'disabled': False, 'open_issues_count': 447, 'license': {'key': 'other', 'name': 'Other', 'spdx_id': 'NOASSERTION', 'url': None, 'node_id': 'MDc6TGljZW5zZTA='}, 'allow_forking': True, 'is_template': False, 'web_commit_signoff_required': False, 'has_pull_requests': True, 'pull_request_creation_policy': 'all', 'topics': ['cpp', 'emulation', 'emulator', 'gamecube', 'wii'], 'visibility': 'public', 'forks': 3162, 'open_issues': 447, 'watchers': 15268, 'default_branch': 'master', 'custom_properties': {}}, 'organization': {'login': 'dolphin-emu', 'id': 5050316, 'node_id': 'MDEyOk9yZ2FuaXphdGlvbjUwNTAzMTY=', 'url': 'https://api.github.com/orgs/dolphin-emu', 'repos_url': 'https://api.github.com/orgs/dolphin-emu/repos', 'events_url': 'https://api.github.com/orgs/dolphin-emu/events', 'hooks_url': 'https://api.github.com/orgs/dolphin-emu/hooks', 'issues_url': 'https://api.github.com/orgs/dolphin-emu/issues', 'members_url': 'https://api.github.com/orgs/dolphin-emu/members{/member}', 'public_members_url': 'https://api.github.com/orgs/dolphin-emu/public_members{/member}', 'avatar_url': 'https://avatars.githubusercontent.com/u/5050316?v=4', 'description': ''}, 'sender': {'login': 'JosJuice', 'id': 6716818, 'node_id': 'MDQ6VXNlcjY3MTY4MTg=', 'avatar_url': 'https://avatars.githubusercontent.com/u/6716818?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/JosJuice', 'html_url': 'https://github.com/JosJuice', 'followers_url': 'https://api.github.com/users/JosJuice/followers', 'following_url': 'https://api.github.com/users/JosJuice/following{/other_user}', 'gists_url': 'https://api.github.com/users/JosJuice/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/JosJuice/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/JosJuice/subscriptions', 'organizations_url': 'https://api.github.com/users/JosJuice/orgs', 'repos_url': 'https://api.github.com/users/JosJuice/repos', 'events_url': 'https://api.github.com/users/JosJuice/events{/privacy}', 'received_events_url': 'https://api.github.com/users/JosJuice/received_events', 'type': 'User', 'user_view_type': 'public', 'site_admin': False}, 'installation': {'id': 35437981, 'node_id': 'MDIzOkludGVncmF0aW9uSW5zdGFsbGF0aW9uMzU0Mzc5ODE='}}, 'type': 'gh_issue_comment'}
2026-07-17T16:56:21.376536	{'source': 'ghhookparser', 'repo': 'dolphin-emu/dolphin', 'author': 'jordan-woyak', 'action': 'created', 'id': 14736, 'title': 'Auto assign wii controllers in netplay', 'url': 'https://github.com/dolphin-emu/dolphin/pull/14736#issuecomment-5005536570', 'safe_author': True, 'body': 'This has been proposed before in #8987 and it was determined to be undesirable because of the many Wii games that use GameCube controllers.\r\n\r\nI think if this was an optional feature in the NetPlay UI then it would be okay.', 'raw': {'action': 'created', 'issue': {'url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/14736', 'repository_url': 'https://api.github.com/repos/dolphin-emu/dolphin', 'labels_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/14736/labels{/name}', 'comments_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/14736/comments', 'events_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/14736/events', 'html_url': 'https://github.com/dolphin-emu/dolphin/pull/14736', 'id': 4911128480, 'node_id': 'PR_kwDOALCn2M7y96iL', 'number': 14736, 'title': 'Auto assign wii controllers in netplay', 'user': {'login': 'tom-pratt', 'id': 10612949, 'node_id': 'MDQ6VXNlcjEwNjEyOTQ5', 'avatar_url': 'https://avatars.githubusercontent.com/u/10612949?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/tom-pratt', 'html_url': 'https://github.com/tom-pratt', 'followers_url': 'https://api.github.com/users/tom-pratt/followers', 'following_url': 'https://api.github.com/users/tom-pratt/following{/other_user}', 'gists_url': 'https://api.github.com/users/tom-pratt/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/tom-pratt/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/tom-pratt/subscriptions', 'organizations_url': 'https://api.github.com/users/tom-pratt/orgs', 'repos_url': 'https://api.github.com/users/tom-pratt/repos', 'events_url': 'https://api.github.com/users/tom-pratt/events{/privacy}', 'received_events_url': 'https://api.github.com/users/tom-pratt/received_events', 'type': 'User', 'user_view_type': 'public', 'site_admin': False}, 'labels': [], 'state': 'open', 'locked': False, 'assignees': [], 'milestone': None, 'comments': 1, 'created_at': '2026-07-17T12:04:49Z', 'updated_at': '2026-07-17T16:56:18Z', 'closed_at': None, 'assignee': None, 'author_association': 'CONTRIBUTOR', 'issue_field_values': [], 'type': None, 'active_lock_reason': None, 'draft': False, 'pull_request': {'url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/14736', 'html_url': 'https://github.com/dolphin-emu/dolphin/pull/14736', 'diff_url': 'https://github.com/dolphin-emu/dolphin/pull/14736.diff', 'patch_url': 'https://github.com/dolphin-emu/dolphin/pull/14736.patch', 'merged_at': None}, 'body': 'Just copy the gamecube logic and automatically assign players to the first empty slot.\r\n\r\nMore consistent with GameCube and helps Android hosts where there is no UI for managing controller mappings currently.', 'reactions': {'url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/14736/reactions', 'total_count': 0, '+1': 0, '-1': 0, 'laugh': 0, 'hooray': 0, 'confused': 0, 'heart': 0, 'rocket': 0, 'eyes': 0}, 'timeline_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/14736/timeline', 'performed_via_github_app': None, 'state_reason': None}, 'comment': {'url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/comments/5005536570', 'html_url': 'https://github.com/dolphin-emu/dolphin/pull/14736#issuecomment-5005536570', 'issue_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/14736', 'id': 5005536570, 'node_id': 'IC_kwDOALCn2M8AAAABKlptOg', 'user': {'login': 'jordan-woyak', 'id': 1768214, 'node_id': 'MDQ6VXNlcjE3NjgyMTQ=', 'avatar_url': 'https://avatars.githubusercontent.com/u/1768214?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/jordan-woyak', 'html_url': 'https://github.com/jordan-woyak', 'followers_url': 'https://api.github.com/users/jordan-woyak/followers', 'following_url': 'https://api.github.com/users/jordan-woyak/following{/other_user}', 'gists_url': 'https://api.github.com/users/jordan-woyak/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/jordan-woyak/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/jordan-woyak/subscriptions', 'organizations_url': 'https://api.github.com/users/jordan-woyak/orgs', 'repos_url': 'https://api.github.com/users/jordan-woyak/repos', 'events_url': 'https://api.github.com/users/jordan-woyak/events{/privacy}', 'received_events_url': 'https://api.github.com/users/jordan-woyak/received_events', 'type': 'User', 'user_view_type': 'public', 'site_admin': False}, 'created_at': '2026-07-17T16:56:18Z', 'updated_at': '2026-07-17T16:56:18Z', 'body': 'This has been proposed before in #8987 and it was determined to be undesirable because of the many Wii games that use GameCube controllers.\r\n\r\nI think if this was an optional feature in the NetPlay UI then it would be okay.', 'author_association': 'MEMBER', 'reactions': {'url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/comments/5005536570/reactions', 'total_count': 0, '+1': 0, '-1': 0, 'laugh': 0, 'hooray': 0, 'confused': 0, 'heart': 0, 'rocket': 0, 'eyes': 0}, 'performed_via_github_app': None, 'minimized': None}, 'repository': {'id': 11577304, 'node_id': 'MDEwOlJlcG9zaXRvcnkxMTU3NzMwNA==', 'name': 'dolphin', 'full_name': 'dolphin-emu/dolphin', 'private': False, 'owner': {'login': 'dolphin-emu', 'id': 5050316, 'node_id': 'MDEyOk9yZ2FuaXphdGlvbjUwNTAzMTY=', 'avatar_url': 'https://avatars.githubusercontent.com/u/5050316?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/dolphin-emu', 'html_url': 'https://github.com/dolphin-emu', 'followers_url': 'https://api.github.com/users/dolphin-emu/followers', 'following_url': 'https://api.github.com/users/dolphin-emu/following{/other_user}', 'gists_url': 'https://api.github.com/users/dolphin-emu/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/dolphin-emu/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/dolphin-emu/subscriptions', 'organizations_url': 'https://api.github.com/users/dolphin-emu/orgs', 'repos_url': 'https://api.github.com/users/dolphin-emu/repos', 'events_url': 'https://api.github.com/users/dolphin-emu/events{/privacy}', 'received_events_url': 'https://api.github.com/users/dolphin-emu/received_events', 'type': 'Organization', 'user_view_type': 'public', 'site_admin': False}, 'html_url': 'https://github.com/dolphin-emu/dolphin', 'description': 'Dolphin is a GameCube / Wii emulator, allowing you to play games for these two platforms on PC with improvements.', 'fork': False, 'url': 'https://api.github.com/repos/dolphin-emu/dolphin', 'forks_url': 'https://api.github.com/repos/dolphin-emu/dolphin/forks', 'keys_url': 'https://api.github.com/repos/dolphin-emu/dolphin/keys{/key_id}', 'collaborators_url': 'https://api.github.com/repos/dolphin-emu/dolphin/collaborators{/collaborator}', 'teams_url': 'https://api.github.com/repos/dolphin-emu/dolphin/teams', 'hooks_url': 'https://api.github.com/repos/dolphin-emu/dolphin/hooks', 'issue_events_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/events{/number}', 'events_url': 'https://api.github.com/repos/dolphin-emu/dolphin/events', 'assignees_url': 'https://api.github.com/repos/dolphin-emu/dolphin/assignees{/user}', 'branches_url': 'https://api.github.com/repos/dolphin-emu/dolphin/branches{/branch}', 'tags_url': 'https://api.github.com/repos/dolphin-emu/dolphin/tags', 'blobs_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/blobs{/sha}', 'git_tags_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/tags{/sha}', 'git_refs_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/refs{/sha}', 'trees_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/trees{/sha}', 'statuses_url': 'https://api.github.com/repos/dolphin-emu/dolphin/statuses/{sha}', 'languages_url': 'https://api.github.com/repos/dolphin-emu/dolphin/languages', 'stargazers_url': 'https://api.github.com/repos/dolphin-emu/dolphin/stargazers', 'contributors_url': 'https://api.github.com/repos/dolphin-emu/dolphin/contributors', 'subscribers_url': 'https://api.github.com/repos/dolphin-emu/dolphin/subscribers', 'subscription_url': 'https://api.github.com/repos/dolphin-emu/dolphin/subscription', 'commits_url': 'https://api.github.com/repos/dolphin-emu/dolphin/commits{/sha}', 'git_commits_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/commits{/sha}', 'comments_url': 'https://api.github.com/repos/dolphin-emu/dolphin/comments{/number}', 'issue_comment_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/comments{/number}', 'contents_url': 'https://api.github.com/repos/dolphin-emu/dolphin/contents/{+path}', 'compare_url': 'https://api.github.com/repos/dolphin-emu/dolphin/compare/{base}...{head}', 'merges_url': 'https://api.github.com/repos/dolphin-emu/dolphin/merges', 'archive_url': 'https://api.github.com/repos/dolphin-emu/dolphin/{archive_format}{/ref}', 'downloads_url': 'https://api.github.com/repos/dolphin-emu/dolphin/downloads', 'issues_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues{/number}', 'pulls_url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls{/number}', 'milestones_url': 'https://api.github.com/repos/dolphin-emu/dolphin/milestones{/number}', 'notifications_url': 'https://api.github.com/repos/dolphin-emu/dolphin/notifications{?since,all,participating}', 'labels_url': 'https://api.github.com/repos/dolphin-emu/dolphin/labels{/name}', 'releases_url': 'https://api.github.com/repos/dolphin-emu/dolphin/releases{/id}', 'deployments_url': 'https://api.github.com/repos/dolphin-emu/dolphin/deployments', 'created_at': '2013-07-22T09:07:57Z', 'updated_at': '2026-07-17T13:03:27Z', 'pushed_at': '2026-07-15T20:58:02Z', 'git_url': 'git://github.com/dolphin-emu/dolphin.git', 'ssh_url': 'git@github.com:dolphin-emu/dolphin.git', 'clone_url': 'https://github.com/dolphin-emu/dolphin.git', 'svn_url': 'https://github.com/dolphin-emu/dolphin', 'homepage': 'https://dolphin-emu.org', 'size': 558444, 'stargazers_count': 15268, 'watchers_count': 15268, 'language': 'C++', 'has_issues': False, 'has_projects': False, 'has_downloads': True, 'has_wiki': True, 'has_pages': False, 'has_discussions': False, 'forks_count': 3162, 'mirror_url': None, 'archived': False, 'disabled': False, 'open_issues_count': 447, 'license': {'key': 'other', 'name': 'Other', 'spdx_id': 'NOASSERTION', 'url': None, 'node_id': 'MDc6TGljZW5zZTA='}, 'allow_forking': True, 'is_template': False, 'web_commit_signoff_required': False, 'has_pull_requests': True, 'pull_request_creation_policy': 'all', 'topics': ['cpp', 'emulation', 'emulator', 'gamecube', 'wii'], 'visibility': 'public', 'forks': 3162, 'open_issues': 447, 'watchers': 15268, 'default_branch': 'master', 'custom_properties': {}}, 'organization': {'login': 'dolphin-emu', 'id': 5050316, 'node_id': 'MDEyOk9yZ2FuaXphdGlvbjUwNTAzMTY=', 'url': 'https://api.github.com/orgs/dolphin-emu', 'repos_url': 'https://api.github.com/orgs/dolphin-emu/repos', 'events_url': 'https://api.github.com/orgs/dolphin-emu/events', 'hooks_url': 'https://api.github.com/orgs/dolphin-emu/hooks', 'issues_url': 'https://api.github.com/orgs/dolphin-emu/issues', 'members_url': 'https://api.github.com/orgs/dolphin-emu/members{/member}', 'public_members_url': 'https://api.github.com/orgs/dolphin-emu/public_members{/member}', 'avatar_url': 'https://avatars.githubusercontent.com/u/5050316?v=4', 'description': ''}, 'sender': {'login': 'jordan-woyak', 'id': 1768214, 'node_id': 'MDQ6VXNlcjE3NjgyMTQ=', 'avatar_url': 'https://avatars.githubusercontent.com/u/1768214?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/jordan-woyak', 'html_url': 'https://github.com/jordan-woyak', 'followers_url': 'https://api.github.com/users/jordan-woyak/followers', 'following_url': 'https://api.github.com/users/jordan-woyak/following{/other_user}', 'gists_url': 'https://api.github.com/users/jordan-woyak/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/jordan-woyak/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/jordan-woyak/subscriptions', 'organizations_url': 'https://api.github.com/users/jordan-woyak/orgs', 'repos_url': 'https://api.github.com/users/jordan-woyak/repos', 'events_url': 'https://api.github.com/users/jordan-woyak/events{/privacy}', 'received_events_url': 'https://api.github.com/users/jordan-woyak/received_events', 'type': 'User', 'user_view_type': 'public', 'site_admin': False}, 'installation': {'id': 35437981, 'node_id': 'MDIzOkludGVncmF0aW9uSW5zdGFsbGF0aW9uMzU0Mzc5ODE='}}, 'type': 'gh_issue_comment'}
2026-07-17T13:47:10.011996	{'source': 'ghhookparser', 'repo': 'dolphin-emu/dolphin', 'author': 'sepalani', 'action': 'created', 'id': 14661, 'title': 'Fix Riivolution Patcher Using Incorrect File Separator on Win', 'url': 'https://github.com/dolphin-emu/dolphin/pull/14661#issuecomment-5003929411', 'safe_author': True, 'body': 'Alright, I managed to replicate the "/" at the end on a portable build. That said, it doesn\'t prevent me from loading the mod and seems to work as intended. So unless I\'m mistaken, it\'s very unlikely for it to be related to the issue you\'re facing.\r\n\r\n<img width="589" height="474" alt="image" src="https://github.com/user-attachments/assets/949be56a-afef-463c-b3d9-459a6a57e229" />\r\n\r\nMoreover, the XML files for the PAL and US regions are ill-formed and don\'t follow the [region\'s specification](https://aerialx.github.io/rvlution.net/wiki/Patch_Format/#ID) properly.\r\n\r\n<img width="1338" height="340" alt="image" src="https://github.com/user-attachments/assets/18d1530d-1ecf-4257-b8fb-c78df3acc614" />\r\n\r\nYou should probably try to clean your current Dolphin setup to see if it fixes the issue and maybe contact the mod\'s author so they fix the non-compliant XML files. If that\'s still failing, you should give us as much pieces of information as possible so we can find a way to be able to reproduce your issue.\r\n\r\nFeel free to join Dolphin Discord server and ping me if you need help related to that matter.', 'raw': {'action': 'created', 'issue': {'url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/14661', 'repository_url': 'https://api.github.com/repos/dolphin-emu/dolphin', 'labels_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/14661/labels{/name}', 'comments_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/14661/comments', 'events_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/14661/events', 'html_url': 'https://github.com/dolphin-emu/dolphin/pull/14661', 'id': 4521311859, 'node_id': 'PR_kwDOALCn2M7fQuBn', 'number': 14661, 'title': 'Fix Riivolution Patcher Using Incorrect File Separator on Win', 'user': {'login': 'nagilson', 'id': 23152278, 'node_id': 'MDQ6VXNlcjIzMTUyMjc4', 'avatar_url': 'https://avatars.githubusercontent.com/u/23152278?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/nagilson', 'html_url': 'https://github.com/nagilson', 'followers_url': 'https://api.github.com/users/nagilson/followers', 'following_url': 'https://api.github.com/users/nagilson/following{/other_user}', 'gists_url': 'https://api.github.com/users/nagilson/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/nagilson/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/nagilson/subscriptions', 'organizations_url': 'https://api.github.com/users/nagilson/orgs', 'repos_url': 'https://api.github.com/users/nagilson/repos', 'events_url': 'https://api.github.com/users/nagilson/events{/privacy}', 'received_events_url': 'https://api.github.com/users/nagilson/received_events', 'type': 'User', 'user_view_type': 'public', 'site_admin': False}, 'labels': [], 'state': 'open', 'locked': False, 'assignees': [], 'milestone': None, 'comments': 11, 'created_at': '2026-05-26T04:17:43Z', 'updated_at': '2026-07-17T13:47:07Z', 'closed_at': None, 'assignee': None, 'author_association': 'NONE', 'issue_field_values': [], 'type': None, 'active_lock_reason': None, 'draft': False, 'pull_request': {'url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/14661', 'html_url': 'https://github.com/dolphin-emu/dolphin/pull/14661', 'diff_url': 'https://github.com/dolphin-emu/dolphin/pull/14661.diff', 'patch_url': 'https://github.com/dolphin-emu/dolphin/pull/14661.patch', 'merged_at': None}, 'body': '# Summary\r\n\r\nThe Riivolution patcher manually manipulated file paths in a way that caused two directory separators to be appended to any subdirectory of a patch, causing riivolution patches to fail to load on windows Dolphin (tested on various versions.)\r\n\r\n# Repro\r\n\r\nThe following is a sure-fire way to repro the issue\r\n\r\n1. Obtain a legal copy of SM Galaxy 2 Using your Console & Disk\r\n2. Download the Super Mario Spectral Mod https://gamebanana.com/mods/387438 and extract it into the riivolution folder(s) (Note: I dont own this mod nor can I confirm it is okay to download, and probably other mods work well too)\r\n3. Try to open the mod on windows, dolphin (latest, dolphin stable, or even dolphin 2024 stable build), by right clicking the .iso or other file extension type, \'Start with Riivolution Patches\'\r\n4. Observe in the logs that the following error occurs, and the mod receives a black screen:\r\n```\r\n Common\\FileUtil.cpp:512 E[COMMON]: ScanDirectoryTree error on C:/Users/REDACTED/Documents/Dolphin Emulator/Load/Riivolution//Spectral/LocalizeData: The system cannot find the path specified.\r\n```\r\n\r\n5. Observe that there are two slashes in the file path which on windows causes an invalid path, assuming the path is functional without the slash. This is not an issue with the configuration of the Riivolution patch XML but an issue with Dolphin.\r\n\r\n> ⚠️  Dolphin also does not respect the preferred windows directory separator char and uses the unix separator but Windows permits this.\r\n\r\n# Alternative Fixes Considered & Breaking Change\r\n\r\n1. For some reason when the riivolution folder is cached / auto-populated, Dolphin ingests a / at the end, but if you open the file explorer and choose the location, the / is removed at the end. \r\n<img width="590" height="279" alt="image_2026-05-25_22-04-50" src="https://github.com/user-attachments/assets/12e17c0e-db67-4888-9607-ff8c09c416ed" />\r\n\r\nIt might be worthwhile to fix the bug there, but I didn\'t want to modify this as it could have other downstream effects and I aimed to have the minimal subset of changes possible.\r\n\r\n2. Ideally we\'d avoid manually modifying the file paths ... as this old comment in the source code used to suggest: https://github.com/hoogmin/dolphin/commit/7ca8dc376745818ab1b1ef3a7092d5f69775b54a, however I decided to make the minimal change possible.\r\n\r\nThis introduces a behavioral change in that, when external_relative_path is empty (or only slashes), the returned path no longer carries a trailing / even if m_sd_root did. I couldn\'t find any dependency on the function or implementation that would break due to this, but I don\'t know this codebase well.\r\n\r\n# Testing\r\n\r\nI created a build of Dolphin and confirmed the fix worked and the riivolution patch now correctly loaded without the errors in the log:\r\n<img width="729" height="572" alt="image" src="https://github.com/user-attachments/assets/8aad8796-7d7b-432b-9daa-6b54b50c32e4" />\r\n\r\nUnit tests are also included.\r\n\r\nNote, to build Dolphin I modified QT to include this instead of the _MSC_VER constraints. \r\n```\r\n# define QT_MAKE_UNCHECKED_ARRAY_ITERATOR(x) (x)\r\n#  define QT_MAKE_CHECKED_ARRAY_ITERATOR(x, N) (x)\r\n```\r\n\r\n', 'reactions': {'url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/14661/reactions', 'total_count': 0, '+1': 0, '-1': 0, 'laugh': 0, 'hooray': 0, 'confused': 0, 'heart': 0, 'rocket': 0, 'eyes': 0}, 'timeline_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/14661/timeline', 'performed_via_github_app': None, 'state_reason': None}, 'comment': {'url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/comments/5003929411', 'html_url': 'https://github.com/dolphin-emu/dolphin/pull/14661#issuecomment-5003929411', 'issue_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/14661', 'id': 5003929411, 'node_id': 'IC_kwDOALCn2M8AAAABKkHnQw', 'user': {'login': 'sepalani', 'id': 7890055, 'node_id': 'MDQ6VXNlcjc4OTAwNTU=', 'avatar_url': 'https://avatars.githubusercontent.com/u/7890055?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/sepalani', 'html_url': 'https://github.com/sepalani', 'followers_url': 'https://api.github.com/users/sepalani/followers', 'following_url': 'https://api.github.com/users/sepalani/following{/other_user}', 'gists_url': 'https://api.github.com/users/sepalani/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/sepalani/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/sepalani/subscriptions', 'organizations_url': 'https://api.github.com/users/sepalani/orgs', 'repos_url': 'https://api.github.com/users/sepalani/repos', 'events_url': 'https://api.github.com/users/sepalani/events{/privacy}', 'received_events_url': 'https://api.github.com/users/sepalani/received_events', 'type': 'User', 'user_view_type': 'public', 'site_admin': False}, 'created_at': '2026-07-17T13:47:07Z', 'updated_at': '2026-07-17T13:47:07Z', 'body': 'Alright, I managed to replicate the "/" at the end on a portable build. That said, it doesn\'t prevent me from loading the mod and seems to work as intended. So unless I\'m mistaken, it\'s very unlikely for it to be related to the issue you\'re facing.\r\n\r\n<img width="589" height="474" alt="image" src="https://github.com/user-attachments/assets/949be56a-afef-463c-b3d9-459a6a57e229" />\r\n\r\nMoreover, the XML files for the PAL and US regions are ill-formed and don\'t follow the [region\'s specification](https://aerialx.github.io/rvlution.net/wiki/Patch_Format/#ID) properly.\r\n\r\n<img width="1338" height="340" alt="image" src="https://github.com/user-attachments/assets/18d1530d-1ecf-4257-b8fb-c78df3acc614" />\r\n\r\nYou should probably try to clean your current Dolphin setup to see if it fixes the issue and maybe contact the mod\'s author so they fix the non-compliant XML files. If that\'s still failing, you should give us as much pieces of information as possible so we can find a way to be able to reproduce your issue.\r\n\r\nFeel free to join Dolphin Discord server and ping me if you need help related to that matter.', 'author_association': 'MEMBER', 'reactions': {'url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/comments/5003929411/reactions', 'total_count': 0, '+1': 0, '-1': 0, 'laugh': 0, 'hooray': 0, 'confused': 0, 'heart': 0, 'rocket': 0, 'eyes': 0}, 'performed_via_github_app': None}, 'repository': {'id': 11577304, 'node_id': 'MDEwOlJlcG9zaXRvcnkxMTU3NzMwNA==', 'name': 'dolphin', 'full_name': 'dolphin-emu/dolphin', 'private': False, 'owner': {'login': 'dolphin-emu', 'id': 5050316, 'node_id': 'MDEyOk9yZ2FuaXphdGlvbjUwNTAzMTY=', 'avatar_url': 'https://avatars.githubusercontent.com/u/5050316?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/dolphin-emu', 'html_url': 'https://github.com/dolphin-emu', 'followers_url': 'https://api.github.com/users/dolphin-emu/followers', 'following_url': 'https://api.github.com/users/dolphin-emu/following{/other_user}', 'gists_url': 'https://api.github.com/users/dolphin-emu/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/dolphin-emu/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/dolphin-emu/subscriptions', 'organizations_url': 'https://api.github.com/users/dolphin-emu/orgs', 'repos_url': 'https://api.github.com/users/dolphin-emu/repos', 'events_url': 'https://api.github.com/users/dolphin-emu/events{/privacy}', 'received_events_url': 'https://api.github.com/users/dolphin-emu/received_events', 'type': 'Organization', 'user_view_type': 'public', 'site_admin': False}, 'html_url': 'https://github.com/dolphin-emu/dolphin', 'description': 'Dolphin is a GameCube / Wii emulator, allowing you to play games for these two platforms on PC with improvements.', 'fork': False, 'url': 'https://api.github.com/repos/dolphin-emu/dolphin', 'forks_url': 'https://api.github.com/repos/dolphin-emu/dolphin/forks', 'keys_url': 'https://api.github.com/repos/dolphin-emu/dolphin/keys{/key_id}', 'collaborators_url': 'https://api.github.com/repos/dolphin-emu/dolphin/collaborators{/collaborator}', 'teams_url': 'https://api.github.com/repos/dolphin-emu/dolphin/teams', 'hooks_url': 'https://api.github.com/repos/dolphin-emu/dolphin/hooks', 'issue_events_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/events{/number}', 'events_url': 'https://api.github.com/repos/dolphin-emu/dolphin/events', 'assignees_url': 'https://api.github.com/repos/dolphin-emu/dolphin/assignees{/user}', 'branches_url': 'https://api.github.com/repos/dolphin-emu/dolphin/branches{/branch}', 'tags_url': 'https://api.github.com/repos/dolphin-emu/dolphin/tags', 'blobs_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/blobs{/sha}', 'git_tags_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/tags{/sha}', 'git_refs_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/refs{/sha}', 'trees_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/trees{/sha}', 'statuses_url': 'https://api.github.com/repos/dolphin-emu/dolphin/statuses/{sha}', 'languages_url': 'https://api.github.com/repos/dolphin-emu/dolphin/languages', 'stargazers_url': 'https://api.github.com/repos/dolphin-emu/dolphin/stargazers', 'contributors_url': 'https://api.github.com/repos/dolphin-emu/dolphin/contributors', 'subscribers_url': 'https://api.github.com/repos/dolphin-emu/dolphin/subscribers', 'subscription_url': 'https://api.github.com/repos/dolphin-emu/dolphin/subscription', 'commits_url': 'https://api.github.com/repos/dolphin-emu/dolphin/commits{/sha}', 'git_commits_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/commits{/sha}', 'comments_url': 'https://api.github.com/repos/dolphin-emu/dolphin/comments{/number}', 'issue_comment_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/comments{/number}', 'contents_url': 'https://api.github.com/repos/dolphin-emu/dolphin/contents/{+path}', 'compare_url': 'https://api.github.com/repos/dolphin-emu/dolphin/compare/{base}...{head}', 'merges_url': 'https://api.github.com/repos/dolphin-emu/dolphin/merges', 'archive_url': 'https://api.github.com/repos/dolphin-emu/dolphin/{archive_format}{/ref}', 'downloads_url': 'https://api.github.com/repos/dolphin-emu/dolphin/downloads', 'issues_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues{/number}', 'pulls_url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls{/number}', 'milestones_url': 'https://api.github.com/repos/dolphin-emu/dolphin/milestones{/number}', 'notifications_url': 'https://api.github.com/repos/dolphin-emu/dolphin/notifications{?since,all,participating}', 'labels_url': 'https://api.github.com/repos/dolphin-emu/dolphin/labels{/name}', 'releases_url': 'https://api.github.com/repos/dolphin-emu/dolphin/releases{/id}', 'deployments_url': 'https://api.github.com/repos/dolphin-emu/dolphin/deployments', 'created_at': '2013-07-22T09:07:57Z', 'updated_at': '2026-07-17T13:03:27Z', 'pushed_at': '2026-07-15T20:58:02Z', 'git_url': 'git://github.com/dolphin-emu/dolphin.git', 'ssh_url': 'git@github.com:dolphin-emu/dolphin.git', 'clone_url': 'https://github.com/dolphin-emu/dolphin.git', 'svn_url': 'https://github.com/dolphin-emu/dolphin', 'homepage': 'https://dolphin-emu.org', 'size': 558444, 'stargazers_count': 15268, 'watchers_count': 15268, 'language': 'C++', 'has_issues': False, 'has_projects': False, 'has_downloads': True, 'has_wiki': True, 'has_pages': False, 'has_discussions': False, 'forks_count': 3162, 'mirror_url': None, 'archived': False, 'disabled': False, 'open_issues_count': 447, 'license': {'key': 'other', 'name': 'Other', 'spdx_id': 'NOASSERTION', 'url': None, 'node_id': 'MDc6TGljZW5zZTA='}, 'allow_forking': True, 'is_template': False, 'web_commit_signoff_required': False, 'has_pull_requests': True, 'pull_request_creation_policy': 'all', 'topics': ['cpp', 'emulation', 'emulator', 'gamecube', 'wii'], 'visibility': 'public', 'forks': 3162, 'open_issues': 447, 'watchers': 15268, 'default_branch': 'master', 'custom_properties': {}}, 'organization': {'login': 'dolphin-emu', 'id': 5050316, 'node_id': 'MDEyOk9yZ2FuaXphdGlvbjUwNTAzMTY=', 'url': 'https://api.github.com/orgs/dolphin-emu', 'repos_url': 'https://api.github.com/orgs/dolphin-emu/repos', 'events_url': 'https://api.github.com/orgs/dolphin-emu/events', 'hooks_url': 'https://api.github.com/orgs/dolphin-emu/hooks', 'issues_url': 'https://api.github.com/orgs/dolphin-emu/issues', 'members_url': 'https://api.github.com/orgs/dolphin-emu/members{/member}', 'public_members_url': 'https://api.github.com/orgs/dolphin-emu/public_members{/member}', 'avatar_url': 'https://avatars.githubusercontent.com/u/5050316?v=4', 'description': ''}, 'sender': {'login': 'sepalani', 'id': 7890055, 'node_id': 'MDQ6VXNlcjc4OTAwNTU=', 'avatar_url': 'https://avatars.githubusercontent.com/u/7890055?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/sepalani', 'html_url': 'https://github.com/sepalani', 'followers_url': 'https://api.github.com/users/sepalani/followers', 'following_url': 'https://api.github.com/users/sepalani/following{/other_user}', 'gists_url': 'https://api.github.com/users/sepalani/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/sepalani/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/sepalani/subscriptions', 'organizations_url': 'https://api.github.com/users/sepalani/orgs', 'repos_url': 'https://api.github.com/users/sepalani/repos', 'events_url': 'https://api.github.com/users/sepalani/events{/privacy}', 'received_events_url': 'https://api.github.com/users/sepalani/received_events', 'type': 'User', 'user_view_type': 'public', 'site_admin': False}, 'installation': {'id': 35437981, 'node_id': 'MDIzOkludGVncmF0aW9uSW5zdGFsbGF0aW9uMzU0Mzc5ODE='}}, 'type': 'gh_issue_comment'}
2026-07-17T06:56:30.340963	{'source': 'ghhookparser', 'repo': 'dolphin-emu/dolphin', 'author': 'DacoTaco', 'action': 'created', 'id': 14651, 'title': 'fixes: make dolreader validate section addresses and sizes', 'url': 'https://github.com/dolphin-emu/dolphin/pull/14651#issuecomment-4999908439', 'safe_author': True, 'body': 'to be fixed in #14733', 'raw': {'action': 'created', 'issue': {'url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/14651', 'repository_url': 'https://api.github.com/repos/dolphin-emu/dolphin', 'labels_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/14651/labels{/name}', 'comments_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/14651/comments', 'events_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/14651/events', 'html_url': 'https://github.com/dolphin-emu/dolphin/pull/14651', 'id': 4440290844, 'node_id': 'PR_kwDOALCn2M7bPTsR', 'number': 14651, 'title': 'fixes: make dolreader validate section addresses and sizes', 'user': {'login': 'DacoTaco', 'id': 12701306, 'node_id': 'MDQ6VXNlcjEyNzAxMzA2', 'avatar_url': 'https://avatars.githubusercontent.com/u/12701306?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/DacoTaco', 'html_url': 'https://github.com/DacoTaco', 'followers_url': 'https://api.github.com/users/DacoTaco/followers', 'following_url': 'https://api.github.com/users/DacoTaco/following{/other_user}', 'gists_url': 'https://api.github.com/users/DacoTaco/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/DacoTaco/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/DacoTaco/subscriptions', 'organizations_url': 'https://api.github.com/users/DacoTaco/orgs', 'repos_url': 'https://api.github.com/users/DacoTaco/repos', 'events_url': 'https://api.github.com/users/DacoTaco/events{/privacy}', 'received_events_url': 'https://api.github.com/users/DacoTaco/received_events', 'type': 'User', 'user_view_type': 'public', 'site_admin': False}, 'labels': [], 'state': 'closed', 'locked': False, 'assignees': [], 'milestone': None, 'comments': 6, 'created_at': '2026-05-13T18:32:53Z', 'updated_at': '2026-07-17T06:56:28Z', 'closed_at': '2026-07-15T05:08:12Z', 'assignee': None, 'author_association': 'CONTRIBUTOR', 'issue_field_values': [], 'type': None, 'active_lock_reason': None, 'draft': False, 'pull_request': {'url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/14651', 'html_url': 'https://github.com/dolphin-emu/dolphin/pull/14651', 'diff_url': 'https://github.com/dolphin-emu/dolphin/pull/14651.diff', 'patch_url': 'https://github.com/dolphin-emu/dolphin/pull/14651.patch', 'merged_at': '2026-07-15T05:08:12Z'}, 'body': "IOS and IPL reject non-32byte aligned sections and with recent libogc changes we didn't notice it until it was to late. \r\nim going over existing tools and documentation so it never happens again :)", 'reactions': {'url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/14651/reactions', 'total_count': 0, '+1': 0, '-1': 0, 'laugh': 0, 'hooray': 0, 'confused': 0, 'heart': 0, 'rocket': 0, 'eyes': 0}, 'timeline_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/14651/timeline', 'performed_via_github_app': None, 'state_reason': None}, 'comment': {'url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/comments/4999908439', 'html_url': 'https://github.com/dolphin-emu/dolphin/pull/14651#issuecomment-4999908439', 'issue_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/14651', 'id': 4999908439, 'node_id': 'IC_kwDOALCn2M8AAAABKgSMVw', 'user': {'login': 'DacoTaco', 'id': 12701306, 'node_id': 'MDQ6VXNlcjEyNzAxMzA2', 'avatar_url': 'https://avatars.githubusercontent.com/u/12701306?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/DacoTaco', 'html_url': 'https://github.com/DacoTaco', 'followers_url': 'https://api.github.com/users/DacoTaco/followers', 'following_url': 'https://api.github.com/users/DacoTaco/following{/other_user}', 'gists_url': 'https://api.github.com/users/DacoTaco/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/DacoTaco/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/DacoTaco/subscriptions', 'organizations_url': 'https://api.github.com/users/DacoTaco/orgs', 'repos_url': 'https://api.github.com/users/DacoTaco/repos', 'events_url': 'https://api.github.com/users/DacoTaco/events{/privacy}', 'received_events_url': 'https://api.github.com/users/DacoTaco/received_events', 'type': 'User', 'user_view_type': 'public', 'site_admin': False}, 'created_at': '2026-07-17T06:56:27Z', 'updated_at': '2026-07-17T06:56:27Z', 'body': 'to be fixed in #14733', 'author_association': 'MEMBER', 'reactions': {'url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/comments/4999908439/reactions', 'total_count': 0, '+1': 0, '-1': 0, 'laugh': 0, 'hooray': 0, 'confused': 0, 'heart': 0, 'rocket': 0, 'eyes': 0}, 'performed_via_github_app': None}, 'repository': {'id': 11577304, 'node_id': 'MDEwOlJlcG9zaXRvcnkxMTU3NzMwNA==', 'name': 'dolphin', 'full_name': 'dolphin-emu/dolphin', 'private': False, 'owner': {'login': 'dolphin-emu', 'id': 5050316, 'node_id': 'MDEyOk9yZ2FuaXphdGlvbjUwNTAzMTY=', 'avatar_url': 'https://avatars.githubusercontent.com/u/5050316?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/dolphin-emu', 'html_url': 'https://github.com/dolphin-emu', 'followers_url': 'https://api.github.com/users/dolphin-emu/followers', 'following_url': 'https://api.github.com/users/dolphin-emu/following{/other_user}', 'gists_url': 'https://api.github.com/users/dolphin-emu/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/dolphin-emu/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/dolphin-emu/subscriptions', 'organizations_url': 'https://api.github.com/users/dolphin-emu/orgs', 'repos_url': 'https://api.github.com/users/dolphin-emu/repos', 'events_url': 'https://api.github.com/users/dolphin-emu/events{/privacy}', 'received_events_url': 'https://api.github.com/users/dolphin-emu/received_events', 'type': 'Organization', 'user_view_type': 'public', 'site_admin': False}, 'html_url': 'https://github.com/dolphin-emu/dolphin', 'description': 'Dolphin is a GameCube / Wii emulator, allowing you to play games for these two platforms on PC with improvements.', 'fork': False, 'url': 'https://api.github.com/repos/dolphin-emu/dolphin', 'forks_url': 'https://api.github.com/repos/dolphin-emu/dolphin/forks', 'keys_url': 'https://api.github.com/repos/dolphin-emu/dolphin/keys{/key_id}', 'collaborators_url': 'https://api.github.com/repos/dolphin-emu/dolphin/collaborators{/collaborator}', 'teams_url': 'https://api.github.com/repos/dolphin-emu/dolphin/teams', 'hooks_url': 'https://api.github.com/repos/dolphin-emu/dolphin/hooks', 'issue_events_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/events{/number}', 'events_url': 'https://api.github.com/repos/dolphin-emu/dolphin/events', 'assignees_url': 'https://api.github.com/repos/dolphin-emu/dolphin/assignees{/user}', 'branches_url': 'https://api.github.com/repos/dolphin-emu/dolphin/branches{/branch}', 'tags_url': 'https://api.github.com/repos/dolphin-emu/dolphin/tags', 'blobs_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/blobs{/sha}', 'git_tags_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/tags{/sha}', 'git_refs_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/refs{/sha}', 'trees_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/trees{/sha}', 'statuses_url': 'https://api.github.com/repos/dolphin-emu/dolphin/statuses/{sha}', 'languages_url': 'https://api.github.com/repos/dolphin-emu/dolphin/languages', 'stargazers_url': 'https://api.github.com/repos/dolphin-emu/dolphin/stargazers', 'contributors_url': 'https://api.github.com/repos/dolphin-emu/dolphin/contributors', 'subscribers_url': 'https://api.github.com/repos/dolphin-emu/dolphin/subscribers', 'subscription_url': 'https://api.github.com/repos/dolphin-emu/dolphin/subscription', 'commits_url': 'https://api.github.com/repos/dolphin-emu/dolphin/commits{/sha}', 'git_commits_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/commits{/sha}', 'comments_url': 'https://api.github.com/repos/dolphin-emu/dolphin/comments{/number}', 'issue_comment_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/comments{/number}', 'contents_url': 'https://api.github.com/repos/dolphin-emu/dolphin/contents/{+path}', 'compare_url': 'https://api.github.com/repos/dolphin-emu/dolphin/compare/{base}...{head}', 'merges_url': 'https://api.github.com/repos/dolphin-emu/dolphin/merges', 'archive_url': 'https://api.github.com/repos/dolphin-emu/dolphin/{archive_format}{/ref}', 'downloads_url': 'https://api.github.com/repos/dolphin-emu/dolphin/downloads', 'issues_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues{/number}', 'pulls_url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls{/number}', 'milestones_url': 'https://api.github.com/repos/dolphin-emu/dolphin/milestones{/number}', 'notifications_url': 'https://api.github.com/repos/dolphin-emu/dolphin/notifications{?since,all,participating}', 'labels_url': 'https://api.github.com/repos/dolphin-emu/dolphin/labels{/name}', 'releases_url': 'https://api.github.com/repos/dolphin-emu/dolphin/releases{/id}', 'deployments_url': 'https://api.github.com/repos/dolphin-emu/dolphin/deployments', 'created_at': '2013-07-22T09:07:57Z', 'updated_at': '2026-07-16T18:41:17Z', 'pushed_at': '2026-07-15T20:58:02Z', 'git_url': 'git://github.com/dolphin-emu/dolphin.git', 'ssh_url': 'git@github.com:dolphin-emu/dolphin.git', 'clone_url': 'https://github.com/dolphin-emu/dolphin.git', 'svn_url': 'https://github.com/dolphin-emu/dolphin', 'homepage': 'https://dolphin-emu.org', 'size': 558444, 'stargazers_count': 15266, 'watchers_count': 15266, 'language': 'C++', 'has_issues': False, 'has_projects': False, 'has_downloads': True, 'has_wiki': True, 'has_pages': False, 'has_discussions': False, 'forks_count': 3162, 'mirror_url': None, 'archived': False, 'disabled': False, 'open_issues_count': 444, 'license': {'key': 'other', 'name': 'Other', 'spdx_id': 'NOASSERTION', 'url': None, 'node_id': 'MDc6TGljZW5zZTA='}, 'allow_forking': True, 'is_template': False, 'web_commit_signoff_required': False, 'has_pull_requests': True, 'pull_request_creation_policy': 'all', 'topics': ['cpp', 'emulation', 'emulator', 'gamecube', 'wii'], 'visibility': 'public', 'forks': 3162, 'open_issues': 444, 'watchers': 15266, 'default_branch': 'master', 'custom_properties': {}}, 'organization': {'login': 'dolphin-emu', 'id': 5050316, 'node_id': 'MDEyOk9yZ2FuaXphdGlvbjUwNTAzMTY=', 'url': 'https://api.github.com/orgs/dolphin-emu', 'repos_url': 'https://api.github.com/orgs/dolphin-emu/repos', 'events_url': 'https://api.github.com/orgs/dolphin-emu/events', 'hooks_url': 'https://api.github.com/orgs/dolphin-emu/hooks', 'issues_url': 'https://api.github.com/orgs/dolphin-emu/issues', 'members_url': 'https://api.github.com/orgs/dolphin-emu/members{/member}', 'public_members_url': 'https://api.github.com/orgs/dolphin-emu/public_members{/member}', 'avatar_url': 'https://avatars.githubusercontent.com/u/5050316?v=4', 'description': ''}, 'sender': {'login': 'DacoTaco', 'id': 12701306, 'node_id': 'MDQ6VXNlcjEyNzAxMzA2', 'avatar_url': 'https://avatars.githubusercontent.com/u/12701306?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/DacoTaco', 'html_url': 'https://github.com/DacoTaco', 'followers_url': 'https://api.github.com/users/DacoTaco/followers', 'following_url': 'https://api.github.com/users/DacoTaco/following{/other_user}', 'gists_url': 'https://api.github.com/users/DacoTaco/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/DacoTaco/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/DacoTaco/subscriptions', 'organizations_url': 'https://api.github.com/users/DacoTaco/orgs', 'repos_url': 'https://api.github.com/users/DacoTaco/repos', 'events_url': 'https://api.github.com/users/DacoTaco/events{/privacy}', 'received_events_url': 'https://api.github.com/users/DacoTaco/received_events', 'type': 'User', 'user_view_type': 'public', 'site_admin': False}, 'installation': {'id': 35437981, 'node_id': 'MDIzOkludGVncmF0aW9uSW5zdGFsbGF0aW9uMzU0Mzc5ODE='}}, 'type': 'gh_issue_comment'}
2026-07-17T01:59:57.561689	{'source': 'ghhookparser', 'repo': 'dolphin-emu/dolphin', 'author': 'dolphin-ci[bot]', 'action': 'created', 'id': 14028, 'title': 'Update tinygltf submodule to v2.9.6', 'url': 'https://github.com/dolphin-emu/dolphin/pull/14028#issuecomment-4998253081', 'safe_author': False, 'body': '[FifoCI](https://fifo.ci/about/) detected that this change impacts graphical             rendering. Here are the [behavior differences](https://fifo.ci/version/39b8eda1cc707b881e74ec9f36a426089eb2ddd1/)             detected by the system:\n\n<details>\n<summary>Detected differences</summary>\n\n||ogl-lin-mesa|vk-lin-mesa|\n|-|-|-|\n|DKCR-Char|[🔍 diff](https://fifo.ci/compare/14828840-14790340/)|[🔍 diff](https://fifo.ci/compare/14827860-14790060/)|\n|DKCR-fast-depth|[🔍 diff](https://fifo.ci/compare/14828861-14790361/)|[🔍 diff](https://fifo.ci/compare/14827881-14790081/)|\n|MaS-LOG-wiimote|[🔍 diff](https://fifo.ci/compare/14828878-14790378/)|[🔍 diff](https://fifo.ci/compare/14827898-14790098/)|\n|aeon-charge-attack|-|[🔍 diff](https://fifo.ci/compare/14827866-14790066/)|\n|burnout2-vehicletextures|[🔍 diff](https://fifo.ci/compare/14828883-14790383/)|[🔍 diff](https://fifo.ci/compare/14827903-14790103/)|\n|chibi-robo-fastdepth|-|[🔍 diff](https://fifo.ci/compare/14827842-14790042/)|\n|chibi-robo-zfighting|-|[🔍 diff](https://fifo.ci/compare/14827808-14790008/)|\n|custom-brawl-char|-|[🔍 diff](https://fifo.ci/compare/14827868-14790068/)|\n|ea-pink|[🔍 diff](https://fifo.ci/compare/14828900-14790400/)|[🔍 diff](https://fifo.ci/compare/14827920-14790120/)|\n|f-zero-rain|[🔍 diff](https://fifo.ci/compare/14828854-14790354/)|[🔍 diff](https://fifo.ci/compare/14827874-14790074/)|\n|fortune-street|-|[🔍 diff](https://fifo.ci/compare/14827827-14790027/)|\n|fortune-street-white-box|-|[🔍 diff](https://fifo.ci/compare/14827829-14790029/)|\n|hotwheels-shadows|-|[🔍 diff](https://fifo.ci/compare/14827942-14790142/)|\n|jd2-fmv|-|[🔍 diff](https://fifo.ci/compare/14827911-14790111/)|\n|jj-awae-mirrored|-|[🔍 diff](https://fifo.ci/compare/14827902-14790102/)|\n|kirby-logicop|[🔍 diff](https://fifo.ci/compare/14828909-14790409/)|[🔍 diff](https://fifo.ci/compare/14827929-14790129/)|\n|kirby-shadows|[🔍 diff](https://fifo.ci/compare/14828796-14790296/)|[🔍 diff](https://fifo.ci/compare/14827816-14790016/)|\n|last-story-shadows|[🔍 diff](https://fifo.ci/compare/14828880-14790380/)|[🔍 diff](https://fifo.ci/compare/14827900-14790100/)|\n|mario-baseball-shadows|-|[🔍 diff](https://fifo.ci/compare/14827895-14790095/)|\n|mario-golf-oob|-|[🔍 diff](https://fifo.ci/compare/14827926-14790126/)|\n|mario-golf-vertex-expansion|[🔍 diff](https://fifo.ci/compare/14828921-14790421/)|[🔍 diff](https://fifo.ci/compare/14827941-14790141/)|\n|mario-sluggers-bar|-|[🔍 diff](https://fifo.ci/compare/14827832-14790032/)|\n|mario-tennis-menu|-|[🔍 diff](https://fifo.ci/compare/14827831-14790031/)|\n|megaman-heat|[🔍 diff](https://fifo.ci/compare/14828816-14790316/)|[🔍 diff](https://fifo.ci/compare/14827836-14790036/)|\n|metroid-visor|[🔍 diff](https://fifo.ci/compare/14828862-14790362/)|[🔍 diff](https://fifo.ci/compare/14827882-14790082/)|\n|milotic-texture|[🔍 diff](https://fifo.ci/compare/14828831-14790331/)|[🔍 diff](https://fifo.ci/compare/14827851-14790051/)|\n|mkdd-efb|-|[🔍 diff](https://fifo.ci/compare/14827819-14790019/)|\n|mkw-bridge|-|[🔍 diff](https://fifo.ci/compare/14827910-14790110/)|\n|mp2-scanner|[🔍 diff](https://fifo.ci/compare/14828885-14790385/)|[🔍 diff](https://fifo.ci/compare/14827905-14790105/)|\n|mp3-bloom|[🔍 diff](https://fifo.ci/compare/14828877-14790377/)|[🔍 diff](https://fifo.ci/compare/14827897-14790097/)|\n|mtennis-zfreeze|[🔍 diff](https://fifo.ci/compare/14828814-14790314/)|[🔍 diff](https://fifo.ci/compare/14827834-14790034/)|\n|nddemo-bumpmapping|[🔍 diff](https://fifo.ci/compare/14828837-14790337/)|[🔍 diff](https://fifo.ci/compare/14827857-14790057/)|\n|nddemo-lighting|[🔍 diff](https://fifo.ci/compare/14828858-14790358/)|[🔍 diff](https://fifo.ci/compare/14827878-14790078/)|\n|nfsu-purplerect|-|[🔍 diff](https://fifo.ci/compare/14827821-14790021/)|\n|nfsu-reflections|-|[🔍 diff](https://fifo.ci/compare/14827811-14790011/)|\n|nhl-slap|[🔍 diff](https://fifo.ci/compare/14828886-14790386/)|[🔍 diff](https://fifo.ci/compare/14827906-14790106/)|\n|nsmbw-coins|-|[🔍 diff](https://fifo.ci/compare/14827864-14790064/)|\n|nsmbw-intro|-|[🔍 diff](https://fifo.ci/compare/14827813-14790013/)|\n|pbr-sfx|[🔍 diff](https://fifo.ci/compare/14828904-14790404/)|[🔍 diff](https://fifo.ci/compare/14827924-14790124/)|\n|pm-hc-jp|-|[🔍 diff](https://fifo.ci/compare/14827859-14790059/)|\n|quake-gx|-|[🔍 diff](https://fifo.ci/compare/14827930-14790130/)|\n|rs2-glass|[🔍 diff](https://fifo.ci/compare/14828819-14790319/)|[🔍 diff](https://fifo.ci/compare/14827839-14790039/)|\n|rs2-zfreeze|-|[🔍 diff](https://fifo.ci/compare/14827822-14790022/)|\n|rs3-bumpmapping|-|[🔍 diff](https://fifo.ci/compare/14827889-14790089/)|\n|sadx-ui|-|[🔍 diff](https://fifo.ci/compare/14827841-14790041/)|\n|sfa-shadows|-|[🔍 diff](https://fifo.ci/compare/14827885-14790085/)|\n|shadow-eyes|-|[🔍 diff](https://fifo.ci/compare/14827916-14790116/)|\n|smb-mirror|-|[🔍 diff](https://fifo.ci/compare/14827909-14790109/)|\n|smg-marioeyes|-|[🔍 diff](https://fifo.ci/compare/14827823-14790023/)|\n|smg-mmg|-|[🔍 diff](https://fifo.ci/compare/14827919-14790119/)|\n|sonic-riders-blur|-|[🔍 diff](https://fifo.ci/compare/14827894-14790094/)|\n|sonic-riders-zg-4p|-|[🔍 diff](https://fifo.ci/compare/14827921-14790121/)|\n|soniccolors-mm|[🔍 diff](https://fifo.ci/compare/14828843-14790343/)|[🔍 diff](https://fifo.ci/compare/14827863-14790063/)|\n|ssbb-mod-lloyd|-|[🔍 diff](https://fifo.ci/compare/14827880-14790080/)|\n|ssbm-pointsize|-|[🔍 diff](https://fifo.ci/compare/14827828-14790028/)|\n|sw3-dt|[🔍 diff](https://fifo.ci/compare/14828864-14790364/)|[🔍 diff](https://fifo.ci/compare/14827884-14790084/)|\n|thps4-shadow|[🔍 diff](https://fifo.ci/compare/14828823-14790323/)|[🔍 diff](https://fifo.ci/compare/14827843-14790043/)|\n|tsp3-pinkgrass|[🔍 diff](https://fifo.ci/compare/14828804-14790304/)|[🔍 diff](https://fifo.ci/compare/14827824-14790024/)|\n|vegas-party-depth|[🔍 diff](https://fifo.ci/compare/14828849-14790349/)|[🔍 diff](https://fifo.ci/compare/14827869-14790069/)|\n|ztp-grass|-|[🔍 diff](https://fifo.ci/compare/14827825-14790025/)|\n|zww-waves|-|[🔍 diff](https://fifo.ci/compare/14827845-14790045/)|\n</details>\n<sub><sup>automated-fifoci-reporter</sup></sub>', 'raw': {'action': 'created', 'issue': {'url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/14028', 'repository_url': 'https://api.github.com/repos/dolphin-emu/dolphin', 'labels_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/14028/labels{/name}', 'comments_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/14028/comments', 'events_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/14028/events', 'html_url': 'https://github.com/dolphin-emu/dolphin/pull/14028', 'id': 3545585344, 'node_id': 'PR_kwDOALCn2M6vT8BS', 'number': 14028, 'title': 'Update tinygltf submodule to v2.9.6', 'user': {'login': 'cscd98', 'id': 1188869, 'node_id': 'MDQ6VXNlcjExODg4Njk=', 'avatar_url': 'https://avatars.githubusercontent.com/u/1188869?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/cscd98', 'html_url': 'https://github.com/cscd98', 'followers_url': 'https://api.github.com/users/cscd98/followers', 'following_url': 'https://api.github.com/users/cscd98/following{/other_user}', 'gists_url': 'https://api.github.com/users/cscd98/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/cscd98/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/cscd98/subscriptions', 'organizations_url': 'https://api.github.com/users/cscd98/orgs', 'repos_url': 'https://api.github.com/users/cscd98/repos', 'events_url': 'https://api.github.com/users/cscd98/events{/privacy}', 'received_events_url': 'https://api.github.com/users/cscd98/received_events', 'type': 'User', 'user_view_type': 'public', 'site_admin': False}, 'labels': [], 'state': 'open', 'locked': False, 'assignees': [], 'milestone': None, 'comments': 2, 'created_at': '2025-10-23T16:39:16Z', 'updated_at': '2026-07-17T01:59:55Z', 'closed_at': None, 'assignee': None, 'author_association': 'CONTRIBUTOR', 'issue_field_values': [], 'type': None, 'active_lock_reason': None, 'draft': False, 'pull_request': {'url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/14028', 'html_url': 'https://github.com/dolphin-emu/dolphin/pull/14028', 'diff_url': 'https://github.com/dolphin-emu/dolphin/pull/14028.diff', 'patch_url': 'https://github.com/dolphin-emu/dolphin/pull/14028.patch', 'merged_at': None}, 'body': None, 'reactions': {'url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/14028/reactions', 'total_count': 0, '+1': 0, '-1': 0, 'laugh': 0, 'hooray': 0, 'confused': 0, 'heart': 0, 'rocket': 0, 'eyes': 0}, 'timeline_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/14028/timeline', 'performed_via_github_app': None, 'state_reason': None}, 'comment': {'url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/comments/4998253081', 'html_url': 'https://github.com/dolphin-emu/dolphin/pull/14028#issuecomment-4998253081', 'issue_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/14028', 'id': 4998253081, 'node_id': 'IC_kwDOALCn2M8AAAABKetKGQ', 'user': {'login': 'dolphin-ci[bot]', 'id': 59266906, 'node_id': 'MDM6Qm90NTkyNjY5MDY=', 'avatar_url': 'https://avatars.githubusercontent.com/in/49947?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/dolphin-ci%5Bbot%5D', 'html_url': 'https://github.com/apps/dolphin-ci', 'followers_url': 'https://api.github.com/users/dolphin-ci%5Bbot%5D/followers', 'following_url': 'https://api.github.com/users/dolphin-ci%5Bbot%5D/following{/other_user}', 'gists_url': 'https://api.github.com/users/dolphin-ci%5Bbot%5D/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/dolphin-ci%5Bbot%5D/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/dolphin-ci%5Bbot%5D/subscriptions', 'organizations_url': 'https://api.github.com/users/dolphin-ci%5Bbot%5D/orgs', 'repos_url': 'https://api.github.com/users/dolphin-ci%5Bbot%5D/repos', 'events_url': 'https://api.github.com/users/dolphin-ci%5Bbot%5D/events{/privacy}', 'received_events_url': 'https://api.github.com/users/dolphin-ci%5Bbot%5D/received_events', 'type': 'Bot', 'user_view_type': 'public', 'site_admin': False}, 'created_at': '2026-07-17T01:59:55Z', 'updated_at': '2026-07-17T01:59:55Z', 'body': '[FifoCI](https://fifo.ci/about/) detected that this change impacts graphical             rendering. Here are the [behavior differences](https://fifo.ci/version/39b8eda1cc707b881e74ec9f36a426089eb2ddd1/)             detected by the system:\n\n<details>\n<summary>Detected differences</summary>\n\n||ogl-lin-mesa|vk-lin-mesa|\n|-|-|-|\n|DKCR-Char|[🔍 diff](https://fifo.ci/compare/14828840-14790340/)|[🔍 diff](https://fifo.ci/compare/14827860-14790060/)|\n|DKCR-fast-depth|[🔍 diff](https://fifo.ci/compare/14828861-14790361/)|[🔍 diff](https://fifo.ci/compare/14827881-14790081/)|\n|MaS-LOG-wiimote|[🔍 diff](https://fifo.ci/compare/14828878-14790378/)|[🔍 diff](https://fifo.ci/compare/14827898-14790098/)|\n|aeon-charge-attack|-|[🔍 diff](https://fifo.ci/compare/14827866-14790066/)|\n|burnout2-vehicletextures|[🔍 diff](https://fifo.ci/compare/14828883-14790383/)|[🔍 diff](https://fifo.ci/compare/14827903-14790103/)|\n|chibi-robo-fastdepth|-|[🔍 diff](https://fifo.ci/compare/14827842-14790042/)|\n|chibi-robo-zfighting|-|[🔍 diff](https://fifo.ci/compare/14827808-14790008/)|\n|custom-brawl-char|-|[🔍 diff](https://fifo.ci/compare/14827868-14790068/)|\n|ea-pink|[🔍 diff](https://fifo.ci/compare/14828900-14790400/)|[🔍 diff](https://fifo.ci/compare/14827920-14790120/)|\n|f-zero-rain|[🔍 diff](https://fifo.ci/compare/14828854-14790354/)|[🔍 diff](https://fifo.ci/compare/14827874-14790074/)|\n|fortune-street|-|[🔍 diff](https://fifo.ci/compare/14827827-14790027/)|\n|fortune-street-white-box|-|[🔍 diff](https://fifo.ci/compare/14827829-14790029/)|\n|hotwheels-shadows|-|[🔍 diff](https://fifo.ci/compare/14827942-14790142/)|\n|jd2-fmv|-|[🔍 diff](https://fifo.ci/compare/14827911-14790111/)|\n|jj-awae-mirrored|-|[🔍 diff](https://fifo.ci/compare/14827902-14790102/)|\n|kirby-logicop|[🔍 diff](https://fifo.ci/compare/14828909-14790409/)|[🔍 diff](https://fifo.ci/compare/14827929-14790129/)|\n|kirby-shadows|[🔍 diff](https://fifo.ci/compare/14828796-14790296/)|[🔍 diff](https://fifo.ci/compare/14827816-14790016/)|\n|last-story-shadows|[🔍 diff](https://fifo.ci/compare/14828880-14790380/)|[🔍 diff](https://fifo.ci/compare/14827900-14790100/)|\n|mario-baseball-shadows|-|[🔍 diff](https://fifo.ci/compare/14827895-14790095/)|\n|mario-golf-oob|-|[🔍 diff](https://fifo.ci/compare/14827926-14790126/)|\n|mario-golf-vertex-expansion|[🔍 diff](https://fifo.ci/compare/14828921-14790421/)|[🔍 diff](https://fifo.ci/compare/14827941-14790141/)|\n|mario-sluggers-bar|-|[🔍 diff](https://fifo.ci/compare/14827832-14790032/)|\n|mario-tennis-menu|-|[🔍 diff](https://fifo.ci/compare/14827831-14790031/)|\n|megaman-heat|[🔍 diff](https://fifo.ci/compare/14828816-14790316/)|[🔍 diff](https://fifo.ci/compare/14827836-14790036/)|\n|metroid-visor|[🔍 diff](https://fifo.ci/compare/14828862-14790362/)|[🔍 diff](https://fifo.ci/compare/14827882-14790082/)|\n|milotic-texture|[🔍 diff](https://fifo.ci/compare/14828831-14790331/)|[🔍 diff](https://fifo.ci/compare/14827851-14790051/)|\n|mkdd-efb|-|[🔍 diff](https://fifo.ci/compare/14827819-14790019/)|\n|mkw-bridge|-|[🔍 diff](https://fifo.ci/compare/14827910-14790110/)|\n|mp2-scanner|[🔍 diff](https://fifo.ci/compare/14828885-14790385/)|[🔍 diff](https://fifo.ci/compare/14827905-14790105/)|\n|mp3-bloom|[🔍 diff](https://fifo.ci/compare/14828877-14790377/)|[🔍 diff](https://fifo.ci/compare/14827897-14790097/)|\n|mtennis-zfreeze|[🔍 diff](https://fifo.ci/compare/14828814-14790314/)|[🔍 diff](https://fifo.ci/compare/14827834-14790034/)|\n|nddemo-bumpmapping|[🔍 diff](https://fifo.ci/compare/14828837-14790337/)|[🔍 diff](https://fifo.ci/compare/14827857-14790057/)|\n|nddemo-lighting|[🔍 diff](https://fifo.ci/compare/14828858-14790358/)|[🔍 diff](https://fifo.ci/compare/14827878-14790078/)|\n|nfsu-purplerect|-|[🔍 diff](https://fifo.ci/compare/14827821-14790021/)|\n|nfsu-reflections|-|[🔍 diff](https://fifo.ci/compare/14827811-14790011/)|\n|nhl-slap|[🔍 diff](https://fifo.ci/compare/14828886-14790386/)|[🔍 diff](https://fifo.ci/compare/14827906-14790106/)|\n|nsmbw-coins|-|[🔍 diff](https://fifo.ci/compare/14827864-14790064/)|\n|nsmbw-intro|-|[🔍 diff](https://fifo.ci/compare/14827813-14790013/)|\n|pbr-sfx|[🔍 diff](https://fifo.ci/compare/14828904-14790404/)|[🔍 diff](https://fifo.ci/compare/14827924-14790124/)|\n|pm-hc-jp|-|[🔍 diff](https://fifo.ci/compare/14827859-14790059/)|\n|quake-gx|-|[🔍 diff](https://fifo.ci/compare/14827930-14790130/)|\n|rs2-glass|[🔍 diff](https://fifo.ci/compare/14828819-14790319/)|[🔍 diff](https://fifo.ci/compare/14827839-14790039/)|\n|rs2-zfreeze|-|[🔍 diff](https://fifo.ci/compare/14827822-14790022/)|\n|rs3-bumpmapping|-|[🔍 diff](https://fifo.ci/compare/14827889-14790089/)|\n|sadx-ui|-|[🔍 diff](https://fifo.ci/compare/14827841-14790041/)|\n|sfa-shadows|-|[🔍 diff](https://fifo.ci/compare/14827885-14790085/)|\n|shadow-eyes|-|[🔍 diff](https://fifo.ci/compare/14827916-14790116/)|\n|smb-mirror|-|[🔍 diff](https://fifo.ci/compare/14827909-14790109/)|\n|smg-marioeyes|-|[🔍 diff](https://fifo.ci/compare/14827823-14790023/)|\n|smg-mmg|-|[🔍 diff](https://fifo.ci/compare/14827919-14790119/)|\n|sonic-riders-blur|-|[🔍 diff](https://fifo.ci/compare/14827894-14790094/)|\n|sonic-riders-zg-4p|-|[🔍 diff](https://fifo.ci/compare/14827921-14790121/)|\n|soniccolors-mm|[🔍 diff](https://fifo.ci/compare/14828843-14790343/)|[🔍 diff](https://fifo.ci/compare/14827863-14790063/)|\n|ssbb-mod-lloyd|-|[🔍 diff](https://fifo.ci/compare/14827880-14790080/)|\n|ssbm-pointsize|-|[🔍 diff](https://fifo.ci/compare/14827828-14790028/)|\n|sw3-dt|[🔍 diff](https://fifo.ci/compare/14828864-14790364/)|[🔍 diff](https://fifo.ci/compare/14827884-14790084/)|\n|thps4-shadow|[🔍 diff](https://fifo.ci/compare/14828823-14790323/)|[🔍 diff](https://fifo.ci/compare/14827843-14790043/)|\n|tsp3-pinkgrass|[🔍 diff](https://fifo.ci/compare/14828804-14790304/)|[🔍 diff](https://fifo.ci/compare/14827824-14790024/)|\n|vegas-party-depth|[🔍 diff](https://fifo.ci/compare/14828849-14790349/)|[🔍 diff](https://fifo.ci/compare/14827869-14790069/)|\n|ztp-grass|-|[🔍 diff](https://fifo.ci/compare/14827825-14790025/)|\n|zww-waves|-|[🔍 diff](https://fifo.ci/compare/14827845-14790045/)|\n</details>\n<sub><sup>automated-fifoci-reporter</sup></sub>', 'author_association': 'NONE', 'reactions': {'url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/comments/4998253081/reactions', 'total_count': 0, '+1': 0, '-1': 0, 'laugh': 0, 'hooray': 0, 'confused': 0, 'heart': 0, 'rocket': 0, 'eyes': 0}, 'performed_via_github_app': {'id': 49947, 'client_id': 'Iv1.1fcaea7644d8b727', 'slug': 'dolphin-ci', 'node_id': 'MDM6QXBwNDk5NDc=', 'owner': {'login': 'dolphin-emu', 'id': 5050316, 'node_id': 'MDEyOk9yZ2FuaXphdGlvbjUwNTAzMTY=', 'avatar_url': 'https://avatars.githubusercontent.com/u/5050316?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/dolphin-emu', 'html_url': 'https://github.com/dolphin-emu', 'followers_url': 'https://api.github.com/users/dolphin-emu/followers', 'following_url': 'https://api.github.com/users/dolphin-emu/following{/other_user}', 'gists_url': 'https://api.github.com/users/dolphin-emu/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/dolphin-emu/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/dolphin-emu/subscriptions', 'organizations_url': 'https://api.github.com/users/dolphin-emu/orgs', 'repos_url': 'https://api.github.com/users/dolphin-emu/repos', 'events_url': 'https://api.github.com/users/dolphin-emu/events{/privacy}', 'received_events_url': 'https://api.github.com/users/dolphin-emu/received_events', 'type': 'Organization', 'user_view_type': 'public', 'site_admin': False}, 'name': 'Dolphin CI', 'description': 'Continuous Integration setup for [dolphin-emu.org](https://dolphin-emu.org/).', 'external_url': 'https://github.com/dolphin-emu', 'html_url': 'https://github.com/apps/dolphin-ci', 'created_at': '2019-12-26T22:26:07Z', 'updated_at': '2019-12-26T22:33:19Z', 'permissions': {'checks': 'write', 'contents': 'read', 'issues': 'write', 'members': 'read', 'metadata': 'read', 'pull_requests': 'write', 'statuses': 'write'}, 'events': ['check_run', 'commit_comment', 'issue_comment', 'pull_request', 'pull_request_review', 'pull_request_review_comment', 'push']}}, 'repository': {'id': 11577304, 'node_id': 'MDEwOlJlcG9zaXRvcnkxMTU3NzMwNA==', 'name': 'dolphin', 'full_name': 'dolphin-emu/dolphin', 'private': False, 'owner': {'login': 'dolphin-emu', 'id': 5050316, 'node_id': 'MDEyOk9yZ2FuaXphdGlvbjUwNTAzMTY=', 'avatar_url': 'https://avatars.githubusercontent.com/u/5050316?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/dolphin-emu', 'html_url': 'https://github.com/dolphin-emu', 'followers_url': 'https://api.github.com/users/dolphin-emu/followers', 'following_url': 'https://api.github.com/users/dolphin-emu/following{/other_user}', 'gists_url': 'https://api.github.com/users/dolphin-emu/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/dolphin-emu/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/dolphin-emu/subscriptions', 'organizations_url': 'https://api.github.com/users/dolphin-emu/orgs', 'repos_url': 'https://api.github.com/users/dolphin-emu/repos', 'events_url': 'https://api.github.com/users/dolphin-emu/events{/privacy}', 'received_events_url': 'https://api.github.com/users/dolphin-emu/received_events', 'type': 'Organization', 'user_view_type': 'public', 'site_admin': False}, 'html_url': 'https://github.com/dolphin-emu/dolphin', 'description': 'Dolphin is a GameCube / Wii emulator, allowing you to play games for these two platforms on PC with improvements.', 'fork': False, 'url': 'https://api.github.com/repos/dolphin-emu/dolphin', 'forks_url': 'https://api.github.com/repos/dolphin-emu/dolphin/forks', 'keys_url': 'https://api.github.com/repos/dolphin-emu/dolphin/keys{/key_id}', 'collaborators_url': 'https://api.github.com/repos/dolphin-emu/dolphin/collaborators{/collaborator}', 'teams_url': 'https://api.github.com/repos/dolphin-emu/dolphin/teams', 'hooks_url': 'https://api.github.com/repos/dolphin-emu/dolphin/hooks', 'issue_events_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/events{/number}', 'events_url': 'https://api.github.com/repos/dolphin-emu/dolphin/events', 'assignees_url': 'https://api.github.com/repos/dolphin-emu/dolphin/assignees{/user}', 'branches_url': 'https://api.github.com/repos/dolphin-emu/dolphin/branches{/branch}', 'tags_url': 'https://api.github.com/repos/dolphin-emu/dolphin/tags', 'blobs_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/blobs{/sha}', 'git_tags_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/tags{/sha}', 'git_refs_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/refs{/sha}', 'trees_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/trees{/sha}', 'statuses_url': 'https://api.github.com/repos/dolphin-emu/dolphin/statuses/{sha}', 'languages_url': 'https://api.github.com/repos/dolphin-emu/dolphin/languages', 'stargazers_url': 'https://api.github.com/repos/dolphin-emu/dolphin/stargazers', 'contributors_url': 'https://api.github.com/repos/dolphin-emu/dolphin/contributors', 'subscribers_url': 'https://api.github.com/repos/dolphin-emu/dolphin/subscribers', 'subscription_url': 'https://api.github.com/repos/dolphin-emu/dolphin/subscription', 'commits_url': 'https://api.github.com/repos/dolphin-emu/dolphin/commits{/sha}', 'git_commits_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/commits{/sha}', 'comments_url': 'https://api.github.com/repos/dolphin-emu/dolphin/comments{/number}', 'issue_comment_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/comments{/number}', 'contents_url': 'https://api.github.com/repos/dolphin-emu/dolphin/contents/{+path}', 'compare_url': 'https://api.github.com/repos/dolphin-emu/dolphin/compare/{base}...{head}', 'merges_url': 'https://api.github.com/repos/dolphin-emu/dolphin/merges', 'archive_url': 'https://api.github.com/repos/dolphin-emu/dolphin/{archive_format}{/ref}', 'downloads_url': 'https://api.github.com/repos/dolphin-emu/dolphin/downloads', 'issues_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues{/number}', 'pulls_url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls{/number}', 'milestones_url': 'https://api.github.com/repos/dolphin-emu/dolphin/milestones{/number}', 'notifications_url': 'https://api.github.com/repos/dolphin-emu/dolphin/notifications{?since,all,participating}', 'labels_url': 'https://api.github.com/repos/dolphin-emu/dolphin/labels{/name}', 'releases_url': 'https://api.github.com/repos/dolphin-emu/dolphin/releases{/id}', 'deployments_url': 'https://api.github.com/repos/dolphin-emu/dolphin/deployments', 'created_at': '2013-07-22T09:07:57Z', 'updated_at': '2026-07-16T18:41:17Z', 'pushed_at': '2026-07-15T20:58:02Z', 'git_url': 'git://github.com/dolphin-emu/dolphin.git', 'ssh_url': 'git@github.com:dolphin-emu/dolphin.git', 'clone_url': 'https://github.com/dolphin-emu/dolphin.git', 'svn_url': 'https://github.com/dolphin-emu/dolphin', 'homepage': 'https://dolphin-emu.org', 'size': 558444, 'stargazers_count': 15266, 'watchers_count': 15266, 'language': 'C++', 'has_issues': False, 'has_projects': False, 'has_downloads': True, 'has_wiki': True, 'has_pages': False, 'has_discussions': False, 'forks_count': 3162, 'mirror_url': None, 'archived': False, 'disabled': False, 'open_issues_count': 443, 'license': {'key': 'other', 'name': 'Other', 'spdx_id': 'NOASSERTION', 'url': None, 'node_id': 'MDc6TGljZW5zZTA='}, 'allow_forking': True, 'is_template': False, 'web_commit_signoff_required': False, 'has_pull_requests': True, 'pull_request_creation_policy': 'all', 'topics': ['cpp', 'emulation', 'emulator', 'gamecube', 'wii'], 'visibility': 'public', 'forks': 3162, 'open_issues': 443, 'watchers': 15266, 'default_branch': 'master', 'custom_properties': {}}, 'organization': {'login': 'dolphin-emu', 'id': 5050316, 'node_id': 'MDEyOk9yZ2FuaXphdGlvbjUwNTAzMTY=', 'url': 'https://api.github.com/orgs/dolphin-emu', 'repos_url': 'https://api.github.com/orgs/dolphin-emu/repos', 'events_url': 'https://api.github.com/orgs/dolphin-emu/events', 'hooks_url': 'https://api.github.com/orgs/dolphin-emu/hooks', 'issues_url': 'https://api.github.com/orgs/dolphin-emu/issues', 'members_url': 'https://api.github.com/orgs/dolphin-emu/members{/member}', 'public_members_url': 'https://api.github.com/orgs/dolphin-emu/public_members{/member}', 'avatar_url': 'https://avatars.githubusercontent.com/u/5050316?v=4', 'description': ''}, 'sender': {'login': 'dolphin-ci[bot]', 'id': 59266906, 'node_id': 'MDM6Qm90NTkyNjY5MDY=', 'avatar_url': 'https://avatars.githubusercontent.com/in/49947?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/dolphin-ci%5Bbot%5D', 'html_url': 'https://github.com/apps/dolphin-ci', 'followers_url': 'https://api.github.com/users/dolphin-ci%5Bbot%5D/followers', 'following_url': 'https://api.github.com/users/dolphin-ci%5Bbot%5D/following{/other_user}', 'gists_url': 'https://api.github.com/users/dolphin-ci%5Bbot%5D/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/dolphin-ci%5Bbot%5D/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/dolphin-ci%5Bbot%5D/subscriptions', 'organizations_url': 'https://api.github.com/users/dolphin-ci%5Bbot%5D/orgs', 'repos_url': 'https://api.github.com/users/dolphin-ci%5Bbot%5D/repos', 'events_url': 'https://api.github.com/users/dolphin-ci%5Bbot%5D/events{/privacy}', 'received_events_url': 'https://api.github.com/users/dolphin-ci%5Bbot%5D/received_events', 'type': 'Bot', 'user_view_type': 'public', 'site_admin': False}, 'installation': {'id': 35437981, 'node_id': 'MDIzOkludGVncmF0aW9uSW5zdGFsbGF0aW9uMzU0Mzc5ODE='}}, 'type': 'gh_issue_comment'}
2026-07-17T01:59:55.885735	{'source': 'ghhookparser', 'repo': 'dolphin-emu/dolphin', 'author': 'dolphin-ci[bot]', 'action': 'deleted', 'id': 14028, 'title': 'Update tinygltf submodule to v2.9.6', 'url': 'https://github.com/dolphin-emu/dolphin/pull/14028#issuecomment-4998167139', 'safe_author': False, 'body': '[FifoCI](https://fifo.ci/about/) detected that this change impacts graphical             rendering. Here are the [behavior differences](https://fifo.ci/version/39b8eda1cc707b881e74ec9f36a426089eb2ddd1/)             detected by the system:\n\n<details>\n<summary>Detected differences</summary>\n\n||vk-lin-mesa|\n|-|-|\n|DKCR-Char|[🔍 diff](https://fifo.ci/compare/14827860-14790060/)|\n|DKCR-fast-depth|[🔍 diff](https://fifo.ci/compare/14827881-14790081/)|\n|MaS-LOG-wiimote|[🔍 diff](https://fifo.ci/compare/14827898-14790098/)|\n|aeon-charge-attack|[🔍 diff](https://fifo.ci/compare/14827866-14790066/)|\n|burnout2-vehicletextures|[🔍 diff](https://fifo.ci/compare/14827903-14790103/)|\n|chibi-robo-fastdepth|[🔍 diff](https://fifo.ci/compare/14827842-14790042/)|\n|chibi-robo-zfighting|[🔍 diff](https://fifo.ci/compare/14827808-14790008/)|\n|custom-brawl-char|[🔍 diff](https://fifo.ci/compare/14827868-14790068/)|\n|ea-pink|[🔍 diff](https://fifo.ci/compare/14827920-14790120/)|\n|f-zero-rain|[🔍 diff](https://fifo.ci/compare/14827874-14790074/)|\n|fortune-street|[🔍 diff](https://fifo.ci/compare/14827827-14790027/)|\n|fortune-street-white-box|[🔍 diff](https://fifo.ci/compare/14827829-14790029/)|\n|hotwheels-shadows|[🔍 diff](https://fifo.ci/compare/14827942-14790142/)|\n|jd2-fmv|[🔍 diff](https://fifo.ci/compare/14827911-14790111/)|\n|jj-awae-mirrored|[🔍 diff](https://fifo.ci/compare/14827902-14790102/)|\n|kirby-logicop|[🔍 diff](https://fifo.ci/compare/14827929-14790129/)|\n|kirby-shadows|[🔍 diff](https://fifo.ci/compare/14827816-14790016/)|\n|last-story-shadows|[🔍 diff](https://fifo.ci/compare/14827900-14790100/)|\n|mario-baseball-shadows|[🔍 diff](https://fifo.ci/compare/14827895-14790095/)|\n|mario-golf-oob|[🔍 diff](https://fifo.ci/compare/14827926-14790126/)|\n|mario-golf-vertex-expansion|[🔍 diff](https://fifo.ci/compare/14827941-14790141/)|\n|mario-sluggers-bar|[🔍 diff](https://fifo.ci/compare/14827832-14790032/)|\n|mario-tennis-menu|[🔍 diff](https://fifo.ci/compare/14827831-14790031/)|\n|megaman-heat|[🔍 diff](https://fifo.ci/compare/14827836-14790036/)|\n|metroid-visor|[🔍 diff](https://fifo.ci/compare/14827882-14790082/)|\n|milotic-texture|[🔍 diff](https://fifo.ci/compare/14827851-14790051/)|\n|mkdd-efb|[🔍 diff](https://fifo.ci/compare/14827819-14790019/)|\n|mkw-bridge|[🔍 diff](https://fifo.ci/compare/14827910-14790110/)|\n|mp2-scanner|[🔍 diff](https://fifo.ci/compare/14827905-14790105/)|\n|mp3-bloom|[🔍 diff](https://fifo.ci/compare/14827897-14790097/)|\n|mtennis-zfreeze|[🔍 diff](https://fifo.ci/compare/14827834-14790034/)|\n|nddemo-bumpmapping|[🔍 diff](https://fifo.ci/compare/14827857-14790057/)|\n|nddemo-lighting|[🔍 diff](https://fifo.ci/compare/14827878-14790078/)|\n|nfsu-purplerect|[🔍 diff](https://fifo.ci/compare/14827821-14790021/)|\n|nfsu-reflections|[🔍 diff](https://fifo.ci/compare/14827811-14790011/)|\n|nhl-slap|[🔍 diff](https://fifo.ci/compare/14827906-14790106/)|\n|nsmbw-coins|[🔍 diff](https://fifo.ci/compare/14827864-14790064/)|\n|nsmbw-intro|[🔍 diff](https://fifo.ci/compare/14827813-14790013/)|\n|pbr-sfx|[🔍 diff](https://fifo.ci/compare/14827924-14790124/)|\n|pm-hc-jp|[🔍 diff](https://fifo.ci/compare/14827859-14790059/)|\n|quake-gx|[🔍 diff](https://fifo.ci/compare/14827930-14790130/)|\n|rs2-glass|[🔍 diff](https://fifo.ci/compare/14827839-14790039/)|\n|rs2-zfreeze|[🔍 diff](https://fifo.ci/compare/14827822-14790022/)|\n|rs3-bumpmapping|[🔍 diff](https://fifo.ci/compare/14827889-14790089/)|\n|sadx-ui|[🔍 diff](https://fifo.ci/compare/14827841-14790041/)|\n|sfa-shadows|[🔍 diff](https://fifo.ci/compare/14827885-14790085/)|\n|shadow-eyes|[🔍 diff](https://fifo.ci/compare/14827916-14790116/)|\n|smb-mirror|[🔍 diff](https://fifo.ci/compare/14827909-14790109/)|\n|smg-marioeyes|[🔍 diff](https://fifo.ci/compare/14827823-14790023/)|\n|smg-mmg|[🔍 diff](https://fifo.ci/compare/14827919-14790119/)|\n|sonic-riders-blur|[🔍 diff](https://fifo.ci/compare/14827894-14790094/)|\n|sonic-riders-zg-4p|[🔍 diff](https://fifo.ci/compare/14827921-14790121/)|\n|soniccolors-mm|[🔍 diff](https://fifo.ci/compare/14827863-14790063/)|\n|ssbb-mod-lloyd|[🔍 diff](https://fifo.ci/compare/14827880-14790080/)|\n|ssbm-pointsize|[🔍 diff](https://fifo.ci/compare/14827828-14790028/)|\n|sw3-dt|[🔍 diff](https://fifo.ci/compare/14827884-14790084/)|\n|thps4-shadow|[🔍 diff](https://fifo.ci/compare/14827843-14790043/)|\n|tsp3-pinkgrass|[🔍 diff](https://fifo.ci/compare/14827824-14790024/)|\n|vegas-party-depth|[🔍 diff](https://fifo.ci/compare/14827869-14790069/)|\n|ztp-grass|[🔍 diff](https://fifo.ci/compare/14827825-14790025/)|\n|zww-waves|[🔍 diff](https://fifo.ci/compare/14827845-14790045/)|\n</details>\n<sub><sup>automated-fifoci-reporter</sup></sub>', 'raw': {'action': 'deleted', 'issue': {'url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/14028', 'repository_url': 'https://api.github.com/repos/dolphin-emu/dolphin', 'labels_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/14028/labels{/name}', 'comments_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/14028/comments', 'events_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/14028/events', 'html_url': 'https://github.com/dolphin-emu/dolphin/pull/14028', 'id': 3545585344, 'node_id': 'PR_kwDOALCn2M6vT8BS', 'number': 14028, 'title': 'Update tinygltf submodule to v2.9.6', 'user': {'login': 'cscd98', 'id': 1188869, 'node_id': 'MDQ6VXNlcjExODg4Njk=', 'avatar_url': 'https://avatars.githubusercontent.com/u/1188869?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/cscd98', 'html_url': 'https://github.com/cscd98', 'followers_url': 'https://api.github.com/users/cscd98/followers', 'following_url': 'https://api.github.com/users/cscd98/following{/other_user}', 'gists_url': 'https://api.github.com/users/cscd98/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/cscd98/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/cscd98/subscriptions', 'organizations_url': 'https://api.github.com/users/cscd98/orgs', 'repos_url': 'https://api.github.com/users/cscd98/repos', 'events_url': 'https://api.github.com/users/cscd98/events{/privacy}', 'received_events_url': 'https://api.github.com/users/cscd98/received_events', 'type': 'User', 'user_view_type': 'public', 'site_admin': False}, 'labels': [], 'state': 'open', 'locked': False, 'assignees': [], 'milestone': None, 'comments': 2, 'created_at': '2025-10-23T16:39:16Z', 'updated_at': '2026-07-17T01:41:59Z', 'closed_at': None, 'assignee': None, 'author_association': 'CONTRIBUTOR', 'issue_field_values': [], 'type': None, 'active_lock_reason': None, 'draft': False, 'pull_request': {'url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/14028', 'html_url': 'https://github.com/dolphin-emu/dolphin/pull/14028', 'diff_url': 'https://github.com/dolphin-emu/dolphin/pull/14028.diff', 'patch_url': 'https://github.com/dolphin-emu/dolphin/pull/14028.patch', 'merged_at': None}, 'body': None, 'reactions': {'url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/14028/reactions', 'total_count': 0, '+1': 0, '-1': 0, 'laugh': 0, 'hooray': 0, 'confused': 0, 'heart': 0, 'rocket': 0, 'eyes': 0}, 'timeline_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/14028/timeline', 'performed_via_github_app': None, 'state_reason': None}, 'comment': {'url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/comments/4998167139', 'html_url': 'https://github.com/dolphin-emu/dolphin/pull/14028#issuecomment-4998167139', 'issue_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/14028', 'id': 4998167139, 'node_id': 'IC_kwDOALCn2M8AAAABKen6Yw', 'user': {'login': 'dolphin-ci[bot]', 'id': 59266906, 'node_id': 'MDM6Qm90NTkyNjY5MDY=', 'avatar_url': 'https://avatars.githubusercontent.com/in/49947?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/dolphin-ci%5Bbot%5D', 'html_url': 'https://github.com/apps/dolphin-ci', 'followers_url': 'https://api.github.com/users/dolphin-ci%5Bbot%5D/followers', 'following_url': 'https://api.github.com/users/dolphin-ci%5Bbot%5D/following{/other_user}', 'gists_url': 'https://api.github.com/users/dolphin-ci%5Bbot%5D/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/dolphin-ci%5Bbot%5D/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/dolphin-ci%5Bbot%5D/subscriptions', 'organizations_url': 'https://api.github.com/users/dolphin-ci%5Bbot%5D/orgs', 'repos_url': 'https://api.github.com/users/dolphin-ci%5Bbot%5D/repos', 'events_url': 'https://api.github.com/users/dolphin-ci%5Bbot%5D/events{/privacy}', 'received_events_url': 'https://api.github.com/users/dolphin-ci%5Bbot%5D/received_events', 'type': 'Bot', 'user_view_type': 'public', 'site_admin': False}, 'created_at': '2026-07-17T01:41:59Z', 'updated_at': '2026-07-17T01:41:59Z', 'body': '[FifoCI](https://fifo.ci/about/) detected that this change impacts graphical             rendering. Here are the [behavior differences](https://fifo.ci/version/39b8eda1cc707b881e74ec9f36a426089eb2ddd1/)             detected by the system:\n\n<details>\n<summary>Detected differences</summary>\n\n||vk-lin-mesa|\n|-|-|\n|DKCR-Char|[🔍 diff](https://fifo.ci/compare/14827860-14790060/)|\n|DKCR-fast-depth|[🔍 diff](https://fifo.ci/compare/14827881-14790081/)|\n|MaS-LOG-wiimote|[🔍 diff](https://fifo.ci/compare/14827898-14790098/)|\n|aeon-charge-attack|[🔍 diff](https://fifo.ci/compare/14827866-14790066/)|\n|burnout2-vehicletextures|[🔍 diff](https://fifo.ci/compare/14827903-14790103/)|\n|chibi-robo-fastdepth|[🔍 diff](https://fifo.ci/compare/14827842-14790042/)|\n|chibi-robo-zfighting|[🔍 diff](https://fifo.ci/compare/14827808-14790008/)|\n|custom-brawl-char|[🔍 diff](https://fifo.ci/compare/14827868-14790068/)|\n|ea-pink|[🔍 diff](https://fifo.ci/compare/14827920-14790120/)|\n|f-zero-rain|[🔍 diff](https://fifo.ci/compare/14827874-14790074/)|\n|fortune-street|[🔍 diff](https://fifo.ci/compare/14827827-14790027/)|\n|fortune-street-white-box|[🔍 diff](https://fifo.ci/compare/14827829-14790029/)|\n|hotwheels-shadows|[🔍 diff](https://fifo.ci/compare/14827942-14790142/)|\n|jd2-fmv|[🔍 diff](https://fifo.ci/compare/14827911-14790111/)|\n|jj-awae-mirrored|[🔍 diff](https://fifo.ci/compare/14827902-14790102/)|\n|kirby-logicop|[🔍 diff](https://fifo.ci/compare/14827929-14790129/)|\n|kirby-shadows|[🔍 diff](https://fifo.ci/compare/14827816-14790016/)|\n|last-story-shadows|[🔍 diff](https://fifo.ci/compare/14827900-14790100/)|\n|mario-baseball-shadows|[🔍 diff](https://fifo.ci/compare/14827895-14790095/)|\n|mario-golf-oob|[🔍 diff](https://fifo.ci/compare/14827926-14790126/)|\n|mario-golf-vertex-expansion|[🔍 diff](https://fifo.ci/compare/14827941-14790141/)|\n|mario-sluggers-bar|[🔍 diff](https://fifo.ci/compare/14827832-14790032/)|\n|mario-tennis-menu|[🔍 diff](https://fifo.ci/compare/14827831-14790031/)|\n|megaman-heat|[🔍 diff](https://fifo.ci/compare/14827836-14790036/)|\n|metroid-visor|[🔍 diff](https://fifo.ci/compare/14827882-14790082/)|\n|milotic-texture|[🔍 diff](https://fifo.ci/compare/14827851-14790051/)|\n|mkdd-efb|[🔍 diff](https://fifo.ci/compare/14827819-14790019/)|\n|mkw-bridge|[🔍 diff](https://fifo.ci/compare/14827910-14790110/)|\n|mp2-scanner|[🔍 diff](https://fifo.ci/compare/14827905-14790105/)|\n|mp3-bloom|[🔍 diff](https://fifo.ci/compare/14827897-14790097/)|\n|mtennis-zfreeze|[🔍 diff](https://fifo.ci/compare/14827834-14790034/)|\n|nddemo-bumpmapping|[🔍 diff](https://fifo.ci/compare/14827857-14790057/)|\n|nddemo-lighting|[🔍 diff](https://fifo.ci/compare/14827878-14790078/)|\n|nfsu-purplerect|[🔍 diff](https://fifo.ci/compare/14827821-14790021/)|\n|nfsu-reflections|[🔍 diff](https://fifo.ci/compare/14827811-14790011/)|\n|nhl-slap|[🔍 diff](https://fifo.ci/compare/14827906-14790106/)|\n|nsmbw-coins|[🔍 diff](https://fifo.ci/compare/14827864-14790064/)|\n|nsmbw-intro|[🔍 diff](https://fifo.ci/compare/14827813-14790013/)|\n|pbr-sfx|[🔍 diff](https://fifo.ci/compare/14827924-14790124/)|\n|pm-hc-jp|[🔍 diff](https://fifo.ci/compare/14827859-14790059/)|\n|quake-gx|[🔍 diff](https://fifo.ci/compare/14827930-14790130/)|\n|rs2-glass|[🔍 diff](https://fifo.ci/compare/14827839-14790039/)|\n|rs2-zfreeze|[🔍 diff](https://fifo.ci/compare/14827822-14790022/)|\n|rs3-bumpmapping|[🔍 diff](https://fifo.ci/compare/14827889-14790089/)|\n|sadx-ui|[🔍 diff](https://fifo.ci/compare/14827841-14790041/)|\n|sfa-shadows|[🔍 diff](https://fifo.ci/compare/14827885-14790085/)|\n|shadow-eyes|[🔍 diff](https://fifo.ci/compare/14827916-14790116/)|\n|smb-mirror|[🔍 diff](https://fifo.ci/compare/14827909-14790109/)|\n|smg-marioeyes|[🔍 diff](https://fifo.ci/compare/14827823-14790023/)|\n|smg-mmg|[🔍 diff](https://fifo.ci/compare/14827919-14790119/)|\n|sonic-riders-blur|[🔍 diff](https://fifo.ci/compare/14827894-14790094/)|\n|sonic-riders-zg-4p|[🔍 diff](https://fifo.ci/compare/14827921-14790121/)|\n|soniccolors-mm|[🔍 diff](https://fifo.ci/compare/14827863-14790063/)|\n|ssbb-mod-lloyd|[🔍 diff](https://fifo.ci/compare/14827880-14790080/)|\n|ssbm-pointsize|[🔍 diff](https://fifo.ci/compare/14827828-14790028/)|\n|sw3-dt|[🔍 diff](https://fifo.ci/compare/14827884-14790084/)|\n|thps4-shadow|[🔍 diff](https://fifo.ci/compare/14827843-14790043/)|\n|tsp3-pinkgrass|[🔍 diff](https://fifo.ci/compare/14827824-14790024/)|\n|vegas-party-depth|[🔍 diff](https://fifo.ci/compare/14827869-14790069/)|\n|ztp-grass|[🔍 diff](https://fifo.ci/compare/14827825-14790025/)|\n|zww-waves|[🔍 diff](https://fifo.ci/compare/14827845-14790045/)|\n</details>\n<sub><sup>automated-fifoci-reporter</sup></sub>', 'author_association': 'NONE', 'reactions': {'url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/comments/4998167139/reactions', 'total_count': 0, '+1': 0, '-1': 0, 'laugh': 0, 'hooray': 0, 'confused': 0, 'heart': 0, 'rocket': 0, 'eyes': 0}, 'performed_via_github_app': {'id': 49947, 'client_id': 'Iv1.1fcaea7644d8b727', 'slug': 'dolphin-ci', 'node_id': 'MDM6QXBwNDk5NDc=', 'owner': {'login': 'dolphin-emu', 'id': 5050316, 'node_id': 'MDEyOk9yZ2FuaXphdGlvbjUwNTAzMTY=', 'avatar_url': 'https://avatars.githubusercontent.com/u/5050316?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/dolphin-emu', 'html_url': 'https://github.com/dolphin-emu', 'followers_url': 'https://api.github.com/users/dolphin-emu/followers', 'following_url': 'https://api.github.com/users/dolphin-emu/following{/other_user}', 'gists_url': 'https://api.github.com/users/dolphin-emu/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/dolphin-emu/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/dolphin-emu/subscriptions', 'organizations_url': 'https://api.github.com/users/dolphin-emu/orgs', 'repos_url': 'https://api.github.com/users/dolphin-emu/repos', 'events_url': 'https://api.github.com/users/dolphin-emu/events{/privacy}', 'received_events_url': 'https://api.github.com/users/dolphin-emu/received_events', 'type': 'Organization', 'user_view_type': 'public', 'site_admin': False}, 'name': 'Dolphin CI', 'description': 'Continuous Integration setup for [dolphin-emu.org](https://dolphin-emu.org/).', 'external_url': 'https://github.com/dolphin-emu', 'html_url': 'https://github.com/apps/dolphin-ci', 'created_at': '2019-12-26T22:26:07Z', 'updated_at': '2019-12-26T22:33:19Z', 'permissions': {'checks': 'write', 'contents': 'read', 'issues': 'write', 'members': 'read', 'metadata': 'read', 'pull_requests': 'write', 'statuses': 'write'}, 'events': ['check_run', 'commit_comment', 'issue_comment', 'pull_request', 'pull_request_review', 'pull_request_review_comment', 'push']}}, 'repository': {'id': 11577304, 'node_id': 'MDEwOlJlcG9zaXRvcnkxMTU3NzMwNA==', 'name': 'dolphin', 'full_name': 'dolphin-emu/dolphin', 'private': False, 'owner': {'login': 'dolphin-emu', 'id': 5050316, 'node_id': 'MDEyOk9yZ2FuaXphdGlvbjUwNTAzMTY=', 'avatar_url': 'https://avatars.githubusercontent.com/u/5050316?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/dolphin-emu', 'html_url': 'https://github.com/dolphin-emu', 'followers_url': 'https://api.github.com/users/dolphin-emu/followers', 'following_url': 'https://api.github.com/users/dolphin-emu/following{/other_user}', 'gists_url': 'https://api.github.com/users/dolphin-emu/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/dolphin-emu/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/dolphin-emu/subscriptions', 'organizations_url': 'https://api.github.com/users/dolphin-emu/orgs', 'repos_url': 'https://api.github.com/users/dolphin-emu/repos', 'events_url': 'https://api.github.com/users/dolphin-emu/events{/privacy}', 'received_events_url': 'https://api.github.com/users/dolphin-emu/received_events', 'type': 'Organization', 'user_view_type': 'public', 'site_admin': False}, 'html_url': 'https://github.com/dolphin-emu/dolphin', 'description': 'Dolphin is a GameCube / Wii emulator, allowing you to play games for these two platforms on PC with improvements.', 'fork': False, 'url': 'https://api.github.com/repos/dolphin-emu/dolphin', 'forks_url': 'https://api.github.com/repos/dolphin-emu/dolphin/forks', 'keys_url': 'https://api.github.com/repos/dolphin-emu/dolphin/keys{/key_id}', 'collaborators_url': 'https://api.github.com/repos/dolphin-emu/dolphin/collaborators{/collaborator}', 'teams_url': 'https://api.github.com/repos/dolphin-emu/dolphin/teams', 'hooks_url': 'https://api.github.com/repos/dolphin-emu/dolphin/hooks', 'issue_events_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/events{/number}', 'events_url': 'https://api.github.com/repos/dolphin-emu/dolphin/events', 'assignees_url': 'https://api.github.com/repos/dolphin-emu/dolphin/assignees{/user}', 'branches_url': 'https://api.github.com/repos/dolphin-emu/dolphin/branches{/branch}', 'tags_url': 'https://api.github.com/repos/dolphin-emu/dolphin/tags', 'blobs_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/blobs{/sha}', 'git_tags_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/tags{/sha}', 'git_refs_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/refs{/sha}', 'trees_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/trees{/sha}', 'statuses_url': 'https://api.github.com/repos/dolphin-emu/dolphin/statuses/{sha}', 'languages_url': 'https://api.github.com/repos/dolphin-emu/dolphin/languages', 'stargazers_url': 'https://api.github.com/repos/dolphin-emu/dolphin/stargazers', 'contributors_url': 'https://api.github.com/repos/dolphin-emu/dolphin/contributors', 'subscribers_url': 'https://api.github.com/repos/dolphin-emu/dolphin/subscribers', 'subscription_url': 'https://api.github.com/repos/dolphin-emu/dolphin/subscription', 'commits_url': 'https://api.github.com/repos/dolphin-emu/dolphin/commits{/sha}', 'git_commits_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/commits{/sha}', 'comments_url': 'https://api.github.com/repos/dolphin-emu/dolphin/comments{/number}', 'issue_comment_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/comments{/number}', 'contents_url': 'https://api.github.com/repos/dolphin-emu/dolphin/contents/{+path}', 'compare_url': 'https://api.github.com/repos/dolphin-emu/dolphin/compare/{base}...{head}', 'merges_url': 'https://api.github.com/repos/dolphin-emu/dolphin/merges', 'archive_url': 'https://api.github.com/repos/dolphin-emu/dolphin/{archive_format}{/ref}', 'downloads_url': 'https://api.github.com/repos/dolphin-emu/dolphin/downloads', 'issues_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues{/number}', 'pulls_url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls{/number}', 'milestones_url': 'https://api.github.com/repos/dolphin-emu/dolphin/milestones{/number}', 'notifications_url': 'https://api.github.com/repos/dolphin-emu/dolphin/notifications{?since,all,participating}', 'labels_url': 'https://api.github.com/repos/dolphin-emu/dolphin/labels{/name}', 'releases_url': 'https://api.github.com/repos/dolphin-emu/dolphin/releases{/id}', 'deployments_url': 'https://api.github.com/repos/dolphin-emu/dolphin/deployments', 'created_at': '2013-07-22T09:07:57Z', 'updated_at': '2026-07-16T18:41:17Z', 'pushed_at': '2026-07-15T20:58:02Z', 'git_url': 'git://github.com/dolphin-emu/dolphin.git', 'ssh_url': 'git@github.com:dolphin-emu/dolphin.git', 'clone_url': 'https://github.com/dolphin-emu/dolphin.git', 'svn_url': 'https://github.com/dolphin-emu/dolphin', 'homepage': 'https://dolphin-emu.org', 'size': 558444, 'stargazers_count': 15266, 'watchers_count': 15266, 'language': 'C++', 'has_issues': False, 'has_projects': False, 'has_downloads': True, 'has_wiki': True, 'has_pages': False, 'has_discussions': False, 'forks_count': 3162, 'mirror_url': None, 'archived': False, 'disabled': False, 'open_issues_count': 443, 'license': {'key': 'other', 'name': 'Other', 'spdx_id': 'NOASSERTION', 'url': None, 'node_id': 'MDc6TGljZW5zZTA='}, 'allow_forking': True, 'is_template': False, 'web_commit_signoff_required': False, 'has_pull_requests': True, 'pull_request_creation_policy': 'all', 'topics': ['cpp', 'emulation', 'emulator', 'gamecube', 'wii'], 'visibility': 'public', 'forks': 3162, 'open_issues': 443, 'watchers': 15266, 'default_branch': 'master', 'custom_properties': {}}, 'organization': {'login': 'dolphin-emu', 'id': 5050316, 'node_id': 'MDEyOk9yZ2FuaXphdGlvbjUwNTAzMTY=', 'url': 'https://api.github.com/orgs/dolphin-emu', 'repos_url': 'https://api.github.com/orgs/dolphin-emu/repos', 'events_url': 'https://api.github.com/orgs/dolphin-emu/events', 'hooks_url': 'https://api.github.com/orgs/dolphin-emu/hooks', 'issues_url': 'https://api.github.com/orgs/dolphin-emu/issues', 'members_url': 'https://api.github.com/orgs/dolphin-emu/members{/member}', 'public_members_url': 'https://api.github.com/orgs/dolphin-emu/public_members{/member}', 'avatar_url': 'https://avatars.githubusercontent.com/u/5050316?v=4', 'description': ''}, 'sender': {'login': 'dolphin-ci[bot]', 'id': 59266906, 'node_id': 'MDM6Qm90NTkyNjY5MDY=', 'avatar_url': 'https://avatars.githubusercontent.com/in/49947?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/dolphin-ci%5Bbot%5D', 'html_url': 'https://github.com/apps/dolphin-ci', 'followers_url': 'https://api.github.com/users/dolphin-ci%5Bbot%5D/followers', 'following_url': 'https://api.github.com/users/dolphin-ci%5Bbot%5D/following{/other_user}', 'gists_url': 'https://api.github.com/users/dolphin-ci%5Bbot%5D/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/dolphin-ci%5Bbot%5D/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/dolphin-ci%5Bbot%5D/subscriptions', 'organizations_url': 'https://api.github.com/users/dolphin-ci%5Bbot%5D/orgs', 'repos_url': 'https://api.github.com/users/dolphin-ci%5Bbot%5D/repos', 'events_url': 'https://api.github.com/users/dolphin-ci%5Bbot%5D/events{/privacy}', 'received_events_url': 'https://api.github.com/users/dolphin-ci%5Bbot%5D/received_events', 'type': 'Bot', 'user_view_type': 'public', 'site_admin': False}, 'installation': {'id': 35437981, 'node_id': 'MDIzOkludGVncmF0aW9uSW5zdGFsbGF0aW9uMzU0Mzc5ODE='}}, 'type': 'gh_issue_comment'}
2026-07-17T01:42:01.982241	{'source': 'ghhookparser', 'repo': 'dolphin-emu/dolphin', 'author': 'dolphin-ci[bot]', 'action': 'created', 'id': 14028, 'title': 'Update tinygltf submodule to v2.9.6', 'url': 'https://github.com/dolphin-emu/dolphin/pull/14028#issuecomment-4998167139', 'safe_author': False, 'body': '[FifoCI](https://fifo.ci/about/) detected that this change impacts graphical             rendering. Here are the [behavior differences](https://fifo.ci/version/39b8eda1cc707b881e74ec9f36a426089eb2ddd1/)             detected by the system:\n\n<details>\n<summary>Detected differences</summary>\n\n||vk-lin-mesa|\n|-|-|\n|DKCR-Char|[🔍 diff](https://fifo.ci/compare/14827860-14790060/)|\n|DKCR-fast-depth|[🔍 diff](https://fifo.ci/compare/14827881-14790081/)|\n|MaS-LOG-wiimote|[🔍 diff](https://fifo.ci/compare/14827898-14790098/)|\n|aeon-charge-attack|[🔍 diff](https://fifo.ci/compare/14827866-14790066/)|\n|burnout2-vehicletextures|[🔍 diff](https://fifo.ci/compare/14827903-14790103/)|\n|chibi-robo-fastdepth|[🔍 diff](https://fifo.ci/compare/14827842-14790042/)|\n|chibi-robo-zfighting|[🔍 diff](https://fifo.ci/compare/14827808-14790008/)|\n|custom-brawl-char|[🔍 diff](https://fifo.ci/compare/14827868-14790068/)|\n|ea-pink|[🔍 diff](https://fifo.ci/compare/14827920-14790120/)|\n|f-zero-rain|[🔍 diff](https://fifo.ci/compare/14827874-14790074/)|\n|fortune-street|[🔍 diff](https://fifo.ci/compare/14827827-14790027/)|\n|fortune-street-white-box|[🔍 diff](https://fifo.ci/compare/14827829-14790029/)|\n|hotwheels-shadows|[🔍 diff](https://fifo.ci/compare/14827942-14790142/)|\n|jd2-fmv|[🔍 diff](https://fifo.ci/compare/14827911-14790111/)|\n|jj-awae-mirrored|[🔍 diff](https://fifo.ci/compare/14827902-14790102/)|\n|kirby-logicop|[🔍 diff](https://fifo.ci/compare/14827929-14790129/)|\n|kirby-shadows|[🔍 diff](https://fifo.ci/compare/14827816-14790016/)|\n|last-story-shadows|[🔍 diff](https://fifo.ci/compare/14827900-14790100/)|\n|mario-baseball-shadows|[🔍 diff](https://fifo.ci/compare/14827895-14790095/)|\n|mario-golf-oob|[🔍 diff](https://fifo.ci/compare/14827926-14790126/)|\n|mario-golf-vertex-expansion|[🔍 diff](https://fifo.ci/compare/14827941-14790141/)|\n|mario-sluggers-bar|[🔍 diff](https://fifo.ci/compare/14827832-14790032/)|\n|mario-tennis-menu|[🔍 diff](https://fifo.ci/compare/14827831-14790031/)|\n|megaman-heat|[🔍 diff](https://fifo.ci/compare/14827836-14790036/)|\n|metroid-visor|[🔍 diff](https://fifo.ci/compare/14827882-14790082/)|\n|milotic-texture|[🔍 diff](https://fifo.ci/compare/14827851-14790051/)|\n|mkdd-efb|[🔍 diff](https://fifo.ci/compare/14827819-14790019/)|\n|mkw-bridge|[🔍 diff](https://fifo.ci/compare/14827910-14790110/)|\n|mp2-scanner|[🔍 diff](https://fifo.ci/compare/14827905-14790105/)|\n|mp3-bloom|[🔍 diff](https://fifo.ci/compare/14827897-14790097/)|\n|mtennis-zfreeze|[🔍 diff](https://fifo.ci/compare/14827834-14790034/)|\n|nddemo-bumpmapping|[🔍 diff](https://fifo.ci/compare/14827857-14790057/)|\n|nddemo-lighting|[🔍 diff](https://fifo.ci/compare/14827878-14790078/)|\n|nfsu-purplerect|[🔍 diff](https://fifo.ci/compare/14827821-14790021/)|\n|nfsu-reflections|[🔍 diff](https://fifo.ci/compare/14827811-14790011/)|\n|nhl-slap|[🔍 diff](https://fifo.ci/compare/14827906-14790106/)|\n|nsmbw-coins|[🔍 diff](https://fifo.ci/compare/14827864-14790064/)|\n|nsmbw-intro|[🔍 diff](https://fifo.ci/compare/14827813-14790013/)|\n|pbr-sfx|[🔍 diff](https://fifo.ci/compare/14827924-14790124/)|\n|pm-hc-jp|[🔍 diff](https://fifo.ci/compare/14827859-14790059/)|\n|quake-gx|[🔍 diff](https://fifo.ci/compare/14827930-14790130/)|\n|rs2-glass|[🔍 diff](https://fifo.ci/compare/14827839-14790039/)|\n|rs2-zfreeze|[🔍 diff](https://fifo.ci/compare/14827822-14790022/)|\n|rs3-bumpmapping|[🔍 diff](https://fifo.ci/compare/14827889-14790089/)|\n|sadx-ui|[🔍 diff](https://fifo.ci/compare/14827841-14790041/)|\n|sfa-shadows|[🔍 diff](https://fifo.ci/compare/14827885-14790085/)|\n|shadow-eyes|[🔍 diff](https://fifo.ci/compare/14827916-14790116/)|\n|smb-mirror|[🔍 diff](https://fifo.ci/compare/14827909-14790109/)|\n|smg-marioeyes|[🔍 diff](https://fifo.ci/compare/14827823-14790023/)|\n|smg-mmg|[🔍 diff](https://fifo.ci/compare/14827919-14790119/)|\n|sonic-riders-blur|[🔍 diff](https://fifo.ci/compare/14827894-14790094/)|\n|sonic-riders-zg-4p|[🔍 diff](https://fifo.ci/compare/14827921-14790121/)|\n|soniccolors-mm|[🔍 diff](https://fifo.ci/compare/14827863-14790063/)|\n|ssbb-mod-lloyd|[🔍 diff](https://fifo.ci/compare/14827880-14790080/)|\n|ssbm-pointsize|[🔍 diff](https://fifo.ci/compare/14827828-14790028/)|\n|sw3-dt|[🔍 diff](https://fifo.ci/compare/14827884-14790084/)|\n|thps4-shadow|[🔍 diff](https://fifo.ci/compare/14827843-14790043/)|\n|tsp3-pinkgrass|[🔍 diff](https://fifo.ci/compare/14827824-14790024/)|\n|vegas-party-depth|[🔍 diff](https://fifo.ci/compare/14827869-14790069/)|\n|ztp-grass|[🔍 diff](https://fifo.ci/compare/14827825-14790025/)|\n|zww-waves|[🔍 diff](https://fifo.ci/compare/14827845-14790045/)|\n</details>\n<sub><sup>automated-fifoci-reporter</sup></sub>', 'raw': {'action': 'created', 'issue': {'url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/14028', 'repository_url': 'https://api.github.com/repos/dolphin-emu/dolphin', 'labels_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/14028/labels{/name}', 'comments_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/14028/comments', 'events_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/14028/events', 'html_url': 'https://github.com/dolphin-emu/dolphin/pull/14028', 'id': 3545585344, 'node_id': 'PR_kwDOALCn2M6vT8BS', 'number': 14028, 'title': 'Update tinygltf submodule to v2.9.6', 'user': {'login': 'cscd98', 'id': 1188869, 'node_id': 'MDQ6VXNlcjExODg4Njk=', 'avatar_url': 'https://avatars.githubusercontent.com/u/1188869?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/cscd98', 'html_url': 'https://github.com/cscd98', 'followers_url': 'https://api.github.com/users/cscd98/followers', 'following_url': 'https://api.github.com/users/cscd98/following{/other_user}', 'gists_url': 'https://api.github.com/users/cscd98/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/cscd98/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/cscd98/subscriptions', 'organizations_url': 'https://api.github.com/users/cscd98/orgs', 'repos_url': 'https://api.github.com/users/cscd98/repos', 'events_url': 'https://api.github.com/users/cscd98/events{/privacy}', 'received_events_url': 'https://api.github.com/users/cscd98/received_events', 'type': 'User', 'user_view_type': 'public', 'site_admin': False}, 'labels': [], 'state': 'open', 'locked': False, 'assignees': [], 'milestone': None, 'comments': 2, 'created_at': '2025-10-23T16:39:16Z', 'updated_at': '2026-07-17T01:41:59Z', 'closed_at': None, 'assignee': None, 'author_association': 'CONTRIBUTOR', 'issue_field_values': [], 'type': None, 'active_lock_reason': None, 'draft': False, 'pull_request': {'url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/14028', 'html_url': 'https://github.com/dolphin-emu/dolphin/pull/14028', 'diff_url': 'https://github.com/dolphin-emu/dolphin/pull/14028.diff', 'patch_url': 'https://github.com/dolphin-emu/dolphin/pull/14028.patch', 'merged_at': None}, 'body': None, 'reactions': {'url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/14028/reactions', 'total_count': 0, '+1': 0, '-1': 0, 'laugh': 0, 'hooray': 0, 'confused': 0, 'heart': 0, 'rocket': 0, 'eyes': 0}, 'timeline_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/14028/timeline', 'performed_via_github_app': None, 'state_reason': None}, 'comment': {'url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/comments/4998167139', 'html_url': 'https://github.com/dolphin-emu/dolphin/pull/14028#issuecomment-4998167139', 'issue_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/14028', 'id': 4998167139, 'node_id': 'IC_kwDOALCn2M8AAAABKen6Yw', 'user': {'login': 'dolphin-ci[bot]', 'id': 59266906, 'node_id': 'MDM6Qm90NTkyNjY5MDY=', 'avatar_url': 'https://avatars.githubusercontent.com/in/49947?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/dolphin-ci%5Bbot%5D', 'html_url': 'https://github.com/apps/dolphin-ci', 'followers_url': 'https://api.github.com/users/dolphin-ci%5Bbot%5D/followers', 'following_url': 'https://api.github.com/users/dolphin-ci%5Bbot%5D/following{/other_user}', 'gists_url': 'https://api.github.com/users/dolphin-ci%5Bbot%5D/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/dolphin-ci%5Bbot%5D/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/dolphin-ci%5Bbot%5D/subscriptions', 'organizations_url': 'https://api.github.com/users/dolphin-ci%5Bbot%5D/orgs', 'repos_url': 'https://api.github.com/users/dolphin-ci%5Bbot%5D/repos', 'events_url': 'https://api.github.com/users/dolphin-ci%5Bbot%5D/events{/privacy}', 'received_events_url': 'https://api.github.com/users/dolphin-ci%5Bbot%5D/received_events', 'type': 'Bot', 'user_view_type': 'public', 'site_admin': False}, 'created_at': '2026-07-17T01:41:59Z', 'updated_at': '2026-07-17T01:41:59Z', 'body': '[FifoCI](https://fifo.ci/about/) detected that this change impacts graphical             rendering. Here are the [behavior differences](https://fifo.ci/version/39b8eda1cc707b881e74ec9f36a426089eb2ddd1/)             detected by the system:\n\n<details>\n<summary>Detected differences</summary>\n\n||vk-lin-mesa|\n|-|-|\n|DKCR-Char|[🔍 diff](https://fifo.ci/compare/14827860-14790060/)|\n|DKCR-fast-depth|[🔍 diff](https://fifo.ci/compare/14827881-14790081/)|\n|MaS-LOG-wiimote|[🔍 diff](https://fifo.ci/compare/14827898-14790098/)|\n|aeon-charge-attack|[🔍 diff](https://fifo.ci/compare/14827866-14790066/)|\n|burnout2-vehicletextures|[🔍 diff](https://fifo.ci/compare/14827903-14790103/)|\n|chibi-robo-fastdepth|[🔍 diff](https://fifo.ci/compare/14827842-14790042/)|\n|chibi-robo-zfighting|[🔍 diff](https://fifo.ci/compare/14827808-14790008/)|\n|custom-brawl-char|[🔍 diff](https://fifo.ci/compare/14827868-14790068/)|\n|ea-pink|[🔍 diff](https://fifo.ci/compare/14827920-14790120/)|\n|f-zero-rain|[🔍 diff](https://fifo.ci/compare/14827874-14790074/)|\n|fortune-street|[🔍 diff](https://fifo.ci/compare/14827827-14790027/)|\n|fortune-street-white-box|[🔍 diff](https://fifo.ci/compare/14827829-14790029/)|\n|hotwheels-shadows|[🔍 diff](https://fifo.ci/compare/14827942-14790142/)|\n|jd2-fmv|[🔍 diff](https://fifo.ci/compare/14827911-14790111/)|\n|jj-awae-mirrored|[🔍 diff](https://fifo.ci/compare/14827902-14790102/)|\n|kirby-logicop|[🔍 diff](https://fifo.ci/compare/14827929-14790129/)|\n|kirby-shadows|[🔍 diff](https://fifo.ci/compare/14827816-14790016/)|\n|last-story-shadows|[🔍 diff](https://fifo.ci/compare/14827900-14790100/)|\n|mario-baseball-shadows|[🔍 diff](https://fifo.ci/compare/14827895-14790095/)|\n|mario-golf-oob|[🔍 diff](https://fifo.ci/compare/14827926-14790126/)|\n|mario-golf-vertex-expansion|[🔍 diff](https://fifo.ci/compare/14827941-14790141/)|\n|mario-sluggers-bar|[🔍 diff](https://fifo.ci/compare/14827832-14790032/)|\n|mario-tennis-menu|[🔍 diff](https://fifo.ci/compare/14827831-14790031/)|\n|megaman-heat|[🔍 diff](https://fifo.ci/compare/14827836-14790036/)|\n|metroid-visor|[🔍 diff](https://fifo.ci/compare/14827882-14790082/)|\n|milotic-texture|[🔍 diff](https://fifo.ci/compare/14827851-14790051/)|\n|mkdd-efb|[🔍 diff](https://fifo.ci/compare/14827819-14790019/)|\n|mkw-bridge|[🔍 diff](https://fifo.ci/compare/14827910-14790110/)|\n|mp2-scanner|[🔍 diff](https://fifo.ci/compare/14827905-14790105/)|\n|mp3-bloom|[🔍 diff](https://fifo.ci/compare/14827897-14790097/)|\n|mtennis-zfreeze|[🔍 diff](https://fifo.ci/compare/14827834-14790034/)|\n|nddemo-bumpmapping|[🔍 diff](https://fifo.ci/compare/14827857-14790057/)|\n|nddemo-lighting|[🔍 diff](https://fifo.ci/compare/14827878-14790078/)|\n|nfsu-purplerect|[🔍 diff](https://fifo.ci/compare/14827821-14790021/)|\n|nfsu-reflections|[🔍 diff](https://fifo.ci/compare/14827811-14790011/)|\n|nhl-slap|[🔍 diff](https://fifo.ci/compare/14827906-14790106/)|\n|nsmbw-coins|[🔍 diff](https://fifo.ci/compare/14827864-14790064/)|\n|nsmbw-intro|[🔍 diff](https://fifo.ci/compare/14827813-14790013/)|\n|pbr-sfx|[🔍 diff](https://fifo.ci/compare/14827924-14790124/)|\n|pm-hc-jp|[🔍 diff](https://fifo.ci/compare/14827859-14790059/)|\n|quake-gx|[🔍 diff](https://fifo.ci/compare/14827930-14790130/)|\n|rs2-glass|[🔍 diff](https://fifo.ci/compare/14827839-14790039/)|\n|rs2-zfreeze|[🔍 diff](https://fifo.ci/compare/14827822-14790022/)|\n|rs3-bumpmapping|[🔍 diff](https://fifo.ci/compare/14827889-14790089/)|\n|sadx-ui|[🔍 diff](https://fifo.ci/compare/14827841-14790041/)|\n|sfa-shadows|[🔍 diff](https://fifo.ci/compare/14827885-14790085/)|\n|shadow-eyes|[🔍 diff](https://fifo.ci/compare/14827916-14790116/)|\n|smb-mirror|[🔍 diff](https://fifo.ci/compare/14827909-14790109/)|\n|smg-marioeyes|[🔍 diff](https://fifo.ci/compare/14827823-14790023/)|\n|smg-mmg|[🔍 diff](https://fifo.ci/compare/14827919-14790119/)|\n|sonic-riders-blur|[🔍 diff](https://fifo.ci/compare/14827894-14790094/)|\n|sonic-riders-zg-4p|[🔍 diff](https://fifo.ci/compare/14827921-14790121/)|\n|soniccolors-mm|[🔍 diff](https://fifo.ci/compare/14827863-14790063/)|\n|ssbb-mod-lloyd|[🔍 diff](https://fifo.ci/compare/14827880-14790080/)|\n|ssbm-pointsize|[🔍 diff](https://fifo.ci/compare/14827828-14790028/)|\n|sw3-dt|[🔍 diff](https://fifo.ci/compare/14827884-14790084/)|\n|thps4-shadow|[🔍 diff](https://fifo.ci/compare/14827843-14790043/)|\n|tsp3-pinkgrass|[🔍 diff](https://fifo.ci/compare/14827824-14790024/)|\n|vegas-party-depth|[🔍 diff](https://fifo.ci/compare/14827869-14790069/)|\n|ztp-grass|[🔍 diff](https://fifo.ci/compare/14827825-14790025/)|\n|zww-waves|[🔍 diff](https://fifo.ci/compare/14827845-14790045/)|\n</details>\n<sub><sup>automated-fifoci-reporter</sup></sub>', 'author_association': 'NONE', 'reactions': {'url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/comments/4998167139/reactions', 'total_count': 0, '+1': 0, '-1': 0, 'laugh': 0, 'hooray': 0, 'confused': 0, 'heart': 0, 'rocket': 0, 'eyes': 0}, 'performed_via_github_app': {'id': 49947, 'client_id': 'Iv1.1fcaea7644d8b727', 'slug': 'dolphin-ci', 'node_id': 'MDM6QXBwNDk5NDc=', 'owner': {'login': 'dolphin-emu', 'id': 5050316, 'node_id': 'MDEyOk9yZ2FuaXphdGlvbjUwNTAzMTY=', 'avatar_url': 'https://avatars.githubusercontent.com/u/5050316?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/dolphin-emu', 'html_url': 'https://github.com/dolphin-emu', 'followers_url': 'https://api.github.com/users/dolphin-emu/followers', 'following_url': 'https://api.github.com/users/dolphin-emu/following{/other_user}', 'gists_url': 'https://api.github.com/users/dolphin-emu/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/dolphin-emu/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/dolphin-emu/subscriptions', 'organizations_url': 'https://api.github.com/users/dolphin-emu/orgs', 'repos_url': 'https://api.github.com/users/dolphin-emu/repos', 'events_url': 'https://api.github.com/users/dolphin-emu/events{/privacy}', 'received_events_url': 'https://api.github.com/users/dolphin-emu/received_events', 'type': 'Organization', 'user_view_type': 'public', 'site_admin': False}, 'name': 'Dolphin CI', 'description': 'Continuous Integration setup for [dolphin-emu.org](https://dolphin-emu.org/).', 'external_url': 'https://github.com/dolphin-emu', 'html_url': 'https://github.com/apps/dolphin-ci', 'created_at': '2019-12-26T22:26:07Z', 'updated_at': '2019-12-26T22:33:19Z', 'permissions': {'checks': 'write', 'contents': 'read', 'issues': 'write', 'members': 'read', 'metadata': 'read', 'pull_requests': 'write', 'statuses': 'write'}, 'events': ['check_run', 'commit_comment', 'issue_comment', 'pull_request', 'pull_request_review', 'pull_request_review_comment', 'push']}}, 'repository': {'id': 11577304, 'node_id': 'MDEwOlJlcG9zaXRvcnkxMTU3NzMwNA==', 'name': 'dolphin', 'full_name': 'dolphin-emu/dolphin', 'private': False, 'owner': {'login': 'dolphin-emu', 'id': 5050316, 'node_id': 'MDEyOk9yZ2FuaXphdGlvbjUwNTAzMTY=', 'avatar_url': 'https://avatars.githubusercontent.com/u/5050316?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/dolphin-emu', 'html_url': 'https://github.com/dolphin-emu', 'followers_url': 'https://api.github.com/users/dolphin-emu/followers', 'following_url': 'https://api.github.com/users/dolphin-emu/following{/other_user}', 'gists_url': 'https://api.github.com/users/dolphin-emu/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/dolphin-emu/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/dolphin-emu/subscriptions', 'organizations_url': 'https://api.github.com/users/dolphin-emu/orgs', 'repos_url': 'https://api.github.com/users/dolphin-emu/repos', 'events_url': 'https://api.github.com/users/dolphin-emu/events{/privacy}', 'received_events_url': 'https://api.github.com/users/dolphin-emu/received_events', 'type': 'Organization', 'user_view_type': 'public', 'site_admin': False}, 'html_url': 'https://github.com/dolphin-emu/dolphin', 'description': 'Dolphin is a GameCube / Wii emulator, allowing you to play games for these two platforms on PC with improvements.', 'fork': False, 'url': 'https://api.github.com/repos/dolphin-emu/dolphin', 'forks_url': 'https://api.github.com/repos/dolphin-emu/dolphin/forks', 'keys_url': 'https://api.github.com/repos/dolphin-emu/dolphin/keys{/key_id}', 'collaborators_url': 'https://api.github.com/repos/dolphin-emu/dolphin/collaborators{/collaborator}', 'teams_url': 'https://api.github.com/repos/dolphin-emu/dolphin/teams', 'hooks_url': 'https://api.github.com/repos/dolphin-emu/dolphin/hooks', 'issue_events_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/events{/number}', 'events_url': 'https://api.github.com/repos/dolphin-emu/dolphin/events', 'assignees_url': 'https://api.github.com/repos/dolphin-emu/dolphin/assignees{/user}', 'branches_url': 'https://api.github.com/repos/dolphin-emu/dolphin/branches{/branch}', 'tags_url': 'https://api.github.com/repos/dolphin-emu/dolphin/tags', 'blobs_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/blobs{/sha}', 'git_tags_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/tags{/sha}', 'git_refs_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/refs{/sha}', 'trees_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/trees{/sha}', 'statuses_url': 'https://api.github.com/repos/dolphin-emu/dolphin/statuses/{sha}', 'languages_url': 'https://api.github.com/repos/dolphin-emu/dolphin/languages', 'stargazers_url': 'https://api.github.com/repos/dolphin-emu/dolphin/stargazers', 'contributors_url': 'https://api.github.com/repos/dolphin-emu/dolphin/contributors', 'subscribers_url': 'https://api.github.com/repos/dolphin-emu/dolphin/subscribers', 'subscription_url': 'https://api.github.com/repos/dolphin-emu/dolphin/subscription', 'commits_url': 'https://api.github.com/repos/dolphin-emu/dolphin/commits{/sha}', 'git_commits_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/commits{/sha}', 'comments_url': 'https://api.github.com/repos/dolphin-emu/dolphin/comments{/number}', 'issue_comment_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/comments{/number}', 'contents_url': 'https://api.github.com/repos/dolphin-emu/dolphin/contents/{+path}', 'compare_url': 'https://api.github.com/repos/dolphin-emu/dolphin/compare/{base}...{head}', 'merges_url': 'https://api.github.com/repos/dolphin-emu/dolphin/merges', 'archive_url': 'https://api.github.com/repos/dolphin-emu/dolphin/{archive_format}{/ref}', 'downloads_url': 'https://api.github.com/repos/dolphin-emu/dolphin/downloads', 'issues_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues{/number}', 'pulls_url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls{/number}', 'milestones_url': 'https://api.github.com/repos/dolphin-emu/dolphin/milestones{/number}', 'notifications_url': 'https://api.github.com/repos/dolphin-emu/dolphin/notifications{?since,all,participating}', 'labels_url': 'https://api.github.com/repos/dolphin-emu/dolphin/labels{/name}', 'releases_url': 'https://api.github.com/repos/dolphin-emu/dolphin/releases{/id}', 'deployments_url': 'https://api.github.com/repos/dolphin-emu/dolphin/deployments', 'created_at': '2013-07-22T09:07:57Z', 'updated_at': '2026-07-16T18:41:17Z', 'pushed_at': '2026-07-15T20:58:02Z', 'git_url': 'git://github.com/dolphin-emu/dolphin.git', 'ssh_url': 'git@github.com:dolphin-emu/dolphin.git', 'clone_url': 'https://github.com/dolphin-emu/dolphin.git', 'svn_url': 'https://github.com/dolphin-emu/dolphin', 'homepage': 'https://dolphin-emu.org', 'size': 558444, 'stargazers_count': 15266, 'watchers_count': 15266, 'language': 'C++', 'has_issues': False, 'has_projects': False, 'has_downloads': True, 'has_wiki': True, 'has_pages': False, 'has_discussions': False, 'forks_count': 3162, 'mirror_url': None, 'archived': False, 'disabled': False, 'open_issues_count': 443, 'license': {'key': 'other', 'name': 'Other', 'spdx_id': 'NOASSERTION', 'url': None, 'node_id': 'MDc6TGljZW5zZTA='}, 'allow_forking': True, 'is_template': False, 'web_commit_signoff_required': False, 'has_pull_requests': True, 'pull_request_creation_policy': 'all', 'topics': ['cpp', 'emulation', 'emulator', 'gamecube', 'wii'], 'visibility': 'public', 'forks': 3162, 'open_issues': 443, 'watchers': 15266, 'default_branch': 'master', 'custom_properties': {}}, 'organization': {'login': 'dolphin-emu', 'id': 5050316, 'node_id': 'MDEyOk9yZ2FuaXphdGlvbjUwNTAzMTY=', 'url': 'https://api.github.com/orgs/dolphin-emu', 'repos_url': 'https://api.github.com/orgs/dolphin-emu/repos', 'events_url': 'https://api.github.com/orgs/dolphin-emu/events', 'hooks_url': 'https://api.github.com/orgs/dolphin-emu/hooks', 'issues_url': 'https://api.github.com/orgs/dolphin-emu/issues', 'members_url': 'https://api.github.com/orgs/dolphin-emu/members{/member}', 'public_members_url': 'https://api.github.com/orgs/dolphin-emu/public_members{/member}', 'avatar_url': 'https://avatars.githubusercontent.com/u/5050316?v=4', 'description': ''}, 'sender': {'login': 'dolphin-ci[bot]', 'id': 59266906, 'node_id': 'MDM6Qm90NTkyNjY5MDY=', 'avatar_url': 'https://avatars.githubusercontent.com/in/49947?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/dolphin-ci%5Bbot%5D', 'html_url': 'https://github.com/apps/dolphin-ci', 'followers_url': 'https://api.github.com/users/dolphin-ci%5Bbot%5D/followers', 'following_url': 'https://api.github.com/users/dolphin-ci%5Bbot%5D/following{/other_user}', 'gists_url': 'https://api.github.com/users/dolphin-ci%5Bbot%5D/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/dolphin-ci%5Bbot%5D/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/dolphin-ci%5Bbot%5D/subscriptions', 'organizations_url': 'https://api.github.com/users/dolphin-ci%5Bbot%5D/orgs', 'repos_url': 'https://api.github.com/users/dolphin-ci%5Bbot%5D/repos', 'events_url': 'https://api.github.com/users/dolphin-ci%5Bbot%5D/events{/privacy}', 'received_events_url': 'https://api.github.com/users/dolphin-ci%5Bbot%5D/received_events', 'type': 'Bot', 'user_view_type': 'public', 'site_admin': False}, 'installation': {'id': 35437981, 'node_id': 'MDIzOkludGVncmF0aW9uSW5zdGFsbGF0aW9uMzU0Mzc5ODE='}}, 'type': 'gh_issue_comment'}

Recent 'gh_pull_request' events

2026-07-18T20:35:06.403479	{'source': 'ghhookparser', 'repo': 'dolphin-emu/dolphin', 'author': 'thethiny', 'action': 'synchronize', 'id': 14731, 'title': 'Convert To WBFS Support', 'base_ref_name': 'master', 'url': 'https://github.com/dolphin-emu/dolphin/pull/14731', 'head_ref_name': 'wbfs-conversion', 'safe_author': False, 'base_sha': 'd3b2943807dd0073f7767947466dd73cccfef319', 'head_sha': '24b41d58df2315831b74f76b95417f2739d02f9d', 'merged': False, 'requested_reviewers': [], 'type': 'gh_pull_request'}
2026-07-18T19:43:31.147726	{'source': 'ghhookparser', 'repo': 'dolphin-emu/dolphin', 'author': 'tygyh', 'action': 'synchronize', 'id': 13025, 'title': 'Core & UnitTests: Join declarations and assignments', 'base_ref_name': 'master', 'url': 'https://github.com/dolphin-emu/dolphin/pull/13025', 'head_ref_name': 'Join-declarations-and-assignments', 'safe_author': True, 'base_sha': '415ec4de182034179143231e84c17dbcdf8be8aa', 'head_sha': '94c3e12bc861a18867fa45602a3e03df6a10a8bf', 'merged': False, 'requested_reviewers': [], 'type': 'gh_pull_request'}
2026-07-18T19:18:52.629828	{'source': 'ghhookparser', 'repo': 'dolphin-emu/dolphin', 'author': 'thethiny', 'action': 'synchronize', 'id': 14731, 'title': 'Convert To WBFS Support', 'base_ref_name': 'master', 'url': 'https://github.com/dolphin-emu/dolphin/pull/14731', 'head_ref_name': 'wbfs-conversion', 'safe_author': False, 'base_sha': 'd3b2943807dd0073f7767947466dd73cccfef319', 'head_sha': 'b1c77c53c795e6c6ee689b83e9b40ab77047d97b', 'merged': False, 'requested_reviewers': [], 'type': 'gh_pull_request'}
2026-07-18T18:58:09.400577	{'source': 'ghhookparser', 'repo': 'dolphin-emu/dolphin', 'author': 'tygyh', 'action': 'synchronize', 'id': 13686, 'title': 'AudioCommon: Integrate FreeSurround partially', 'base_ref_name': 'master', 'url': 'https://github.com/dolphin-emu/dolphin/pull/13686', 'head_ref_name': 'AudioCommon/Integrate-FreeSurround-partially', 'safe_author': True, 'base_sha': '415ec4de182034179143231e84c17dbcdf8be8aa', 'head_sha': '18bf78360e21dac7b28eabf6fdcc3e86b69f7aff', 'merged': False, 'requested_reviewers': [], 'type': 'gh_pull_request'}
2026-07-18T18:47:13.947081	{'source': 'ghhookparser', 'repo': 'dolphin-emu/dolphin', 'author': 'tygyh', 'action': 'synchronize', 'id': 13686, 'title': 'AudioCommon: Integrate FreeSurround partially', 'base_ref_name': 'master', 'url': 'https://github.com/dolphin-emu/dolphin/pull/13686', 'head_ref_name': 'AudioCommon/Integrate-FreeSurround-partially', 'safe_author': True, 'base_sha': '415ec4de182034179143231e84c17dbcdf8be8aa', 'head_sha': '69e8e6868408a1072eb78bd71f34efc8a8da32f1', 'merged': False, 'requested_reviewers': [], 'type': 'gh_pull_request'}
2026-07-18T18:38:56.801574	{'source': 'ghhookparser', 'repo': 'dolphin-emu/dolphin', 'author': 'tygyh', 'action': 'synchronize', 'id': 13686, 'title': 'AudioCommon: Integrate FreeSurround partially', 'base_ref_name': 'master', 'url': 'https://github.com/dolphin-emu/dolphin/pull/13686', 'head_ref_name': 'AudioCommon/Integrate-FreeSurround-partially', 'safe_author': True, 'base_sha': '2e22a3cf425caae0a3cb52cc4deca7008209955f', 'head_sha': '9e8c595196045de98d6a683ad21037c57a96ad82', 'merged': False, 'requested_reviewers': [], 'type': 'gh_pull_request'}
2026-07-18T10:34:55.855197	{'source': 'ghhookparser', 'repo': 'dolphin-emu/dolphin', 'author': 'JosJuice', 'action': 'closed', 'id': 14673, 'title': 'Android: Route DolphinBar Balance Board to the Balance Board slot', 'base_ref_name': 'master', 'url': 'https://github.com/dolphin-emu/dolphin/pull/14673', 'head_ref_name': 'android-dolphinbar-balance-board', 'safe_author': True, 'base_sha': '774200dcf4ccea148ef357cc8cf86d8eab4446da', 'head_sha': '342115806beb93a1f14dd9e40b6839148d70b986', 'merged': True, 'requested_reviewers': [], 'type': 'gh_pull_request'}
2026-07-17T22:27:09.352055	{'source': 'ghhookparser', 'repo': 'dolphin-emu/dolphin', 'author': 'thethiny', 'action': 'synchronize', 'id': 14731, 'title': 'Convert To WBFS Support', 'base_ref_name': 'master', 'url': 'https://github.com/dolphin-emu/dolphin/pull/14731', 'head_ref_name': 'wbfs-conversion', 'safe_author': False, 'base_sha': 'd3b2943807dd0073f7767947466dd73cccfef319', 'head_sha': '81f336974c3eb2f93c05073734d2d7dc16309a6a', 'merged': False, 'requested_reviewers': [], 'type': 'gh_pull_request'}
2026-07-17T12:40:26.506468	{'source': 'ghhookparser', 'repo': 'dolphin-emu/dolphin', 'author': 'DacoTaco', 'action': 'synchronize', 'id': 14733, 'title': 'fixes: dont error on dol section alignment on wii', 'base_ref_name': 'master', 'url': 'https://github.com/dolphin-emu/dolphin/pull/14733', 'head_ref_name': 'fixes/dolalignment', 'safe_author': True, 'base_sha': 'b6d8bc299ee7d03496d624b2e6b9a18d70522435', 'head_sha': 'f0954b8bb060b7154f6be5d2326e8a2f7b6c46d5', 'merged': False, 'requested_reviewers': [], 'type': 'gh_pull_request'}
2026-07-17T12:10:22.497258	{'source': 'ghhookparser', 'repo': 'dolphin-emu/dolphin', 'author': 'tom-pratt', 'action': 'synchronize', 'id': 14734, 'title': 'Android: Trigger netplay game digest check', 'base_ref_name': 'master', 'url': 'https://github.com/dolphin-emu/dolphin/pull/14734', 'head_ref_name': 'trigger-game-digest-check', 'safe_author': True, 'base_sha': 'b6d8bc299ee7d03496d624b2e6b9a18d70522435', 'head_sha': 'fb0cec70395fdaac5524c2881a7f1041c1e627df', 'merged': False, 'requested_reviewers': [], 'type': 'gh_pull_request'}
2026-07-17T12:04:52.341170	{'source': 'ghhookparser', 'repo': 'dolphin-emu/dolphin', 'author': 'tom-pratt', 'action': 'opened', 'id': 14736, 'title': 'Auto assign wii controllers in netplay', 'base_ref_name': 'master', 'url': 'https://github.com/dolphin-emu/dolphin/pull/14736', 'head_ref_name': 'wii-controller-netplay', 'safe_author': True, 'base_sha': 'b6d8bc299ee7d03496d624b2e6b9a18d70522435', 'head_sha': 'e58f57f6f3f7bc517887f5ef6d22741ff1af4900', 'merged': False, 'requested_reviewers': [], 'type': 'gh_pull_request'}
2026-07-17T11:34:47.000549	{'source': 'ghhookparser', 'repo': 'dolphin-emu/dolphin', 'author': 'tom-pratt', 'action': 'opened', 'id': 14735, 'title': 'Android: Dual core warning when hosting netplay', 'base_ref_name': 'master', 'url': 'https://github.com/dolphin-emu/dolphin/pull/14735', 'head_ref_name': 'dual-core-warning', 'safe_author': True, 'base_sha': 'b6d8bc299ee7d03496d624b2e6b9a18d70522435', 'head_sha': '41ffcdd2724d957b1b3383f2bea8272b8487a21b', 'merged': False, 'requested_reviewers': [], 'type': 'gh_pull_request'}
2026-07-17T11:26:58.380581	{'source': 'ghhookparser', 'repo': 'dolphin-emu/dolphin', 'author': 'tom-pratt', 'action': 'opened', 'id': 14734, 'title': 'Android: Trigger netplay game digest check', 'base_ref_name': 'master', 'url': 'https://github.com/dolphin-emu/dolphin/pull/14734', 'head_ref_name': 'trigger-game-digest-check', 'safe_author': True, 'base_sha': 'b6d8bc299ee7d03496d624b2e6b9a18d70522435', 'head_sha': 'b3e4330f8fd2f70eede3e7b4147eac8d7f7d0225', 'merged': False, 'requested_reviewers': [], 'type': 'gh_pull_request'}
2026-07-17T07:28:18.703049	{'source': 'ghhookparser', 'repo': 'dolphin-emu/dolphin', 'author': 'DacoTaco', 'action': 'synchronize', 'id': 14733, 'title': 'fixes: dont error on dol section alignment on wii', 'base_ref_name': 'master', 'url': 'https://github.com/dolphin-emu/dolphin/pull/14733', 'head_ref_name': 'fixes/dolalignment', 'safe_author': True, 'base_sha': 'b6d8bc299ee7d03496d624b2e6b9a18d70522435', 'head_sha': '52e2e859da84b3bd683c423543afed8d22dae63a', 'merged': False, 'requested_reviewers': [], 'type': 'gh_pull_request'}
2026-07-17T07:26:38.255594	{'source': 'ghhookparser', 'repo': 'dolphin-emu/dolphin', 'author': 'DacoTaco', 'action': 'synchronize', 'id': 14733, 'title': 'fixes: dont error on dol section alignment on wii', 'base_ref_name': 'master', 'url': 'https://github.com/dolphin-emu/dolphin/pull/14733', 'head_ref_name': 'fixes/dolalignment', 'safe_author': True, 'base_sha': 'b6d8bc299ee7d03496d624b2e6b9a18d70522435', 'head_sha': 'c8c6851741aade77ed1acb81d18475bf92ebda6a', 'merged': False, 'requested_reviewers': [], 'type': 'gh_pull_request'}
2026-07-17T07:08:26.268008	{'source': 'ghhookparser', 'repo': 'dolphin-emu/dolphin', 'author': 'DacoTaco', 'action': 'synchronize', 'id': 14733, 'title': 'fixes: dont error on dol section alignment on wii', 'base_ref_name': 'master', 'url': 'https://github.com/dolphin-emu/dolphin/pull/14733', 'head_ref_name': 'fixes/dolalignment', 'safe_author': True, 'base_sha': 'b6d8bc299ee7d03496d624b2e6b9a18d70522435', 'head_sha': '2251de78703d99c9a2bc5777b191e25f03bd3992', 'merged': False, 'requested_reviewers': [], 'type': 'gh_pull_request'}
2026-07-17T06:55:55.583380	{'source': 'ghhookparser', 'repo': 'dolphin-emu/dolphin', 'author': 'DacoTaco', 'action': 'synchronize', 'id': 14733, 'title': 'fixes: dont error on dol section alignment on wii', 'base_ref_name': 'master', 'url': 'https://github.com/dolphin-emu/dolphin/pull/14733', 'head_ref_name': 'fixes/dolalignment', 'safe_author': True, 'base_sha': 'b6d8bc299ee7d03496d624b2e6b9a18d70522435', 'head_sha': '9bea4201d9483ab71491dae85d781489c64b392d', 'merged': False, 'requested_reviewers': [], 'type': 'gh_pull_request'}
2026-07-17T06:42:02.662692	{'source': 'ghhookparser', 'repo': 'dolphin-emu/dolphin', 'author': 'DacoTaco', 'action': 'opened', 'id': 14733, 'title': 'fixes: dont error on dol section alignment on wii', 'base_ref_name': 'master', 'url': 'https://github.com/dolphin-emu/dolphin/pull/14733', 'head_ref_name': 'fixes/dolalignment', 'safe_author': True, 'base_sha': 'b6d8bc299ee7d03496d624b2e6b9a18d70522435', 'head_sha': '4a93aa071ba6ed691abac148f30bcd87b9dc99c3', 'merged': False, 'requested_reviewers': [], 'type': 'gh_pull_request'}
2026-07-16T21:53:03.656159	{'source': 'ghhookparser', 'repo': 'dolphin-emu/dolphin', 'author': 'thethiny', 'action': 'synchronize', 'id': 14731, 'title': 'Convert To WBFS Support', 'base_ref_name': 'master', 'url': 'https://github.com/dolphin-emu/dolphin/pull/14731', 'head_ref_name': 'wbfs-conversion', 'safe_author': False, 'base_sha': 'd3b2943807dd0073f7767947466dd73cccfef319', 'head_sha': '8b5134c1512bc3393fa904c43896bb2d3cee1a42', 'merged': False, 'requested_reviewers': [], 'type': 'gh_pull_request'}
2026-07-16T18:26:38.047882	{'source': 'ghhookparser', 'repo': 'dolphin-emu/dolphin', 'author': 'Linkinworm', 'action': 'synchronize', 'id': 14605, 'title': 'Android: GBA systems added', 'base_ref_name': 'master', 'url': 'https://github.com/dolphin-emu/dolphin/pull/14605', 'head_ref_name': 'Android_GBA_Enabler', 'safe_author': True, 'base_sha': '34311f5fa255c5f5737e6775d026eb02279aecaf', 'head_sha': '42b86ffc628e93ea0506f415f3ecc7265928e350', 'merged': False, 'requested_reviewers': [], 'type': 'gh_pull_request'}
2026-07-15T20:58:04.106556	{'source': 'ghhookparser', 'repo': 'dolphin-emu/dolphin', 'author': 'phire', 'action': 'closed', 'id': 14726, 'title': 'GCAdapter: Deregister callback when scan thread exits', 'base_ref_name': 'master', 'url': 'https://github.com/dolphin-emu/dolphin/pull/14726', 'head_ref_name': 'gcadapter-deregister-on-thread-end', 'safe_author': True, 'base_sha': 'fc9fd6952a62c4fe48acc00333ce360cb47b57c7', 'head_sha': '05855a37f4d6b9e98e41e7c50983faa167ae03ac', 'merged': True, 'requested_reviewers': [], 'type': 'gh_pull_request'}
2026-07-15T20:08:15.213460	{'source': 'ghhookparser', 'repo': 'dolphin-emu/dolphin', 'author': 'AdmiralCurtiss', 'action': 'closed', 'id': 14732, 'title': 'IOS/ES: Prevent reading TMDs that are too small', 'base_ref_name': 'master', 'url': 'https://github.com/dolphin-emu/dolphin/pull/14732', 'head_ref_name': 'small-tmd-check', 'safe_author': True, 'base_sha': 'fd8391a85241d1b359d662342c5c66f8f4b96d10', 'head_sha': '900febec29bcfee8b7a1319ec74d9cb1bfb9d157', 'merged': True, 'requested_reviewers': [], 'type': 'gh_pull_request'}
2026-07-15T19:21:05.275332	{'source': 'ghhookparser', 'repo': 'dolphin-emu/dolphin', 'author': 'BeezBumba', 'action': 'synchronize', 'id': 14652, 'title': 'Add Standalone Wayland Support', 'base_ref_name': 'master', 'url': 'https://github.com/dolphin-emu/dolphin/pull/14652', 'head_ref_name': 'merge-wayland', 'safe_author': False, 'base_sha': 'fd8391a85241d1b359d662342c5c66f8f4b96d10', 'head_sha': 'e0e0901c2f93f92bc7d707ba0ae9efe289f54eac', 'merged': False, 'requested_reviewers': [], 'type': 'gh_pull_request'}
2026-07-15T19:18:50.751882	{'source': 'ghhookparser', 'repo': 'dolphin-emu/dolphin', 'author': 'BeezBumba', 'action': 'synchronize', 'id': 14652, 'title': 'Add Standalone Wayland Support', 'base_ref_name': 'master', 'url': 'https://github.com/dolphin-emu/dolphin/pull/14652', 'head_ref_name': 'merge-wayland', 'safe_author': False, 'base_sha': 'fd8391a85241d1b359d662342c5c66f8f4b96d10', 'head_sha': 'f185b23e695eb5652c07dcea20fe749a33d685dd', 'merged': False, 'requested_reviewers': [], 'type': 'gh_pull_request'}
2026-07-15T19:18:23.254970	{'source': 'ghhookparser', 'repo': 'dolphin-emu/dolphin', 'author': 'BeezBumba', 'action': 'synchronize', 'id': 14652, 'title': 'Add Standalone Wayland Support', 'base_ref_name': 'master', 'url': 'https://github.com/dolphin-emu/dolphin/pull/14652', 'head_ref_name': 'merge-wayland', 'safe_author': False, 'base_sha': 'fd8391a85241d1b359d662342c5c66f8f4b96d10', 'head_sha': 'cea1fe1c6ae0402ea8826f527adce6940cb8e456', 'merged': False, 'requested_reviewers': [], 'type': 'gh_pull_request'}

Recent 'gh_pull_request_comment' events

2026-07-18T23:41:29.024924	{'source': 'ghhookparser', 'repo': 'dolphin-emu/dolphin', 'author': 'phire', 'action': 'created', 'id': 14731, 'hash': '24b41d58df2315831b74f76b95417f2739d02f9d', 'url': 'https://github.com/dolphin-emu/dolphin/pull/14731#discussion_r3609425504', 'is_part_of_review': False, 'type': 'gh_pull_request_comment'}
2026-07-18T23:37:37.476236	{'source': 'ghhookparser', 'repo': 'dolphin-emu/dolphin', 'author': 'thethiny', 'action': 'created', 'id': 14731, 'hash': '24b41d58df2315831b74f76b95417f2739d02f9d', 'url': 'https://github.com/dolphin-emu/dolphin/pull/14731#discussion_r3609419546', 'is_part_of_review': False, 'type': 'gh_pull_request_comment'}
2026-07-18T23:36:12.676808	{'source': 'ghhookparser', 'repo': 'dolphin-emu/dolphin', 'author': 'thethiny', 'action': 'created', 'id': 14731, 'hash': '24b41d58df2315831b74f76b95417f2739d02f9d', 'url': 'https://github.com/dolphin-emu/dolphin/pull/14731#discussion_r3609417157', 'is_part_of_review': False, 'type': 'gh_pull_request_comment'}
2026-07-18T23:33:15.219849	{'source': 'ghhookparser', 'repo': 'dolphin-emu/dolphin', 'author': 'thethiny', 'action': 'created', 'id': 14731, 'hash': '24b41d58df2315831b74f76b95417f2739d02f9d', 'url': 'https://github.com/dolphin-emu/dolphin/pull/14731#discussion_r3609413351', 'is_part_of_review': False, 'type': 'gh_pull_request_comment'}
2026-07-18T23:29:02.353189	{'source': 'ghhookparser', 'repo': 'dolphin-emu/dolphin', 'author': 'thethiny', 'action': 'created', 'id': 14731, 'hash': '24b41d58df2315831b74f76b95417f2739d02f9d', 'url': 'https://github.com/dolphin-emu/dolphin/pull/14731#discussion_r3609408071', 'is_part_of_review': False, 'type': 'gh_pull_request_comment'}
2026-07-18T23:14:48.024466	{'source': 'ghhookparser', 'repo': 'dolphin-emu/dolphin', 'author': 'phire', 'action': 'created', 'id': 14731, 'hash': '24b41d58df2315831b74f76b95417f2739d02f9d', 'url': 'https://github.com/dolphin-emu/dolphin/pull/14731#discussion_r3609382108', 'is_part_of_review': False, 'type': 'gh_pull_request_comment'}
2026-07-18T23:06:02.348160	{'source': 'ghhookparser', 'repo': 'dolphin-emu/dolphin', 'author': 'phire', 'action': 'created', 'id': 14731, 'hash': '24b41d58df2315831b74f76b95417f2739d02f9d', 'url': 'https://github.com/dolphin-emu/dolphin/pull/14731#discussion_r3609363364', 'is_part_of_review': True, 'type': 'gh_pull_request_comment'}
2026-07-18T23:03:38.971199	{'source': 'ghhookparser', 'repo': 'dolphin-emu/dolphin', 'author': 'phire', 'action': 'edited', 'id': 14731, 'hash': '24b41d58df2315831b74f76b95417f2739d02f9d', 'url': 'https://github.com/dolphin-emu/dolphin/pull/14731#discussion_r3609277919', 'is_part_of_review': False, 'type': 'gh_pull_request_comment'}
2026-07-18T22:26:25.662974	{'source': 'ghhookparser', 'repo': 'dolphin-emu/dolphin', 'author': 'phire', 'action': 'created', 'id': 14731, 'hash': '24b41d58df2315831b74f76b95417f2739d02f9d', 'url': 'https://github.com/dolphin-emu/dolphin/pull/14731#discussion_r3609268698', 'is_part_of_review': True, 'type': 'gh_pull_request_comment'}
2026-07-18T22:26:25.644251	{'source': 'ghhookparser', 'repo': 'dolphin-emu/dolphin', 'author': 'phire', 'action': 'created', 'id': 14731, 'hash': '24b41d58df2315831b74f76b95417f2739d02f9d', 'url': 'https://github.com/dolphin-emu/dolphin/pull/14731#discussion_r3609277919', 'is_part_of_review': True, 'type': 'gh_pull_request_comment'}
2026-07-18T22:26:25.597100	{'source': 'ghhookparser', 'repo': 'dolphin-emu/dolphin', 'author': 'phire', 'action': 'created', 'id': 14731, 'hash': '24b41d58df2315831b74f76b95417f2739d02f9d', 'url': 'https://github.com/dolphin-emu/dolphin/pull/14731#discussion_r3609296950', 'is_part_of_review': True, 'type': 'gh_pull_request_comment'}
2026-07-18T22:26:25.588213	{'source': 'ghhookparser', 'repo': 'dolphin-emu/dolphin', 'author': 'phire', 'action': 'created', 'id': 14731, 'hash': '24b41d58df2315831b74f76b95417f2739d02f9d', 'url': 'https://github.com/dolphin-emu/dolphin/pull/14731#discussion_r3609262932', 'is_part_of_review': True, 'type': 'gh_pull_request_comment'}
2026-07-18T22:26:25.587510	{'source': 'ghhookparser', 'repo': 'dolphin-emu/dolphin', 'author': 'phire', 'action': 'created', 'id': 14731, 'hash': '24b41d58df2315831b74f76b95417f2739d02f9d', 'url': 'https://github.com/dolphin-emu/dolphin/pull/14731#discussion_r3609251889', 'is_part_of_review': True, 'type': 'gh_pull_request_comment'}
2026-07-18T22:26:25.586923	{'source': 'ghhookparser', 'repo': 'dolphin-emu/dolphin', 'author': 'phire', 'action': 'created', 'id': 14731, 'hash': '24b41d58df2315831b74f76b95417f2739d02f9d', 'url': 'https://github.com/dolphin-emu/dolphin/pull/14731#discussion_r3609258421', 'is_part_of_review': True, 'type': 'gh_pull_request_comment'}
2026-07-18T22:26:25.586310	{'source': 'ghhookparser', 'repo': 'dolphin-emu/dolphin', 'author': 'phire', 'action': 'created', 'id': 14731, 'hash': '24b41d58df2315831b74f76b95417f2739d02f9d', 'url': 'https://github.com/dolphin-emu/dolphin/pull/14731#discussion_r3609218797', 'is_part_of_review': True, 'type': 'gh_pull_request_comment'}
2026-07-18T20:47:17.771514	{'source': 'ghhookparser', 'repo': 'dolphin-emu/dolphin', 'author': 'thethiny', 'action': 'created', 'id': 14731, 'hash': '81f336974c3eb2f93c05073734d2d7dc16309a6a', 'url': 'https://github.com/dolphin-emu/dolphin/pull/14731#discussion_r3609166128', 'is_part_of_review': True, 'type': 'gh_pull_request_comment'}
2026-07-18T20:45:50.555644	{'source': 'ghhookparser', 'repo': 'dolphin-emu/dolphin', 'author': 'thethiny', 'action': 'created', 'id': 14731, 'hash': '24b41d58df2315831b74f76b95417f2739d02f9d', 'url': 'https://github.com/dolphin-emu/dolphin/pull/14731#discussion_r3609163923', 'is_part_of_review': False, 'type': 'gh_pull_request_comment'}
2026-07-18T20:45:07.346294	{'source': 'ghhookparser', 'repo': 'dolphin-emu/dolphin', 'author': 'thethiny', 'action': 'edited', 'id': 14731, 'hash': '81f336974c3eb2f93c05073734d2d7dc16309a6a', 'url': 'https://github.com/dolphin-emu/dolphin/pull/14731#discussion_r3609162555', 'is_part_of_review': False, 'type': 'gh_pull_request_comment'}
2026-07-18T20:44:52.062995	{'source': 'ghhookparser', 'repo': 'dolphin-emu/dolphin', 'author': 'thethiny', 'action': 'created', 'id': 14731, 'hash': '81f336974c3eb2f93c05073734d2d7dc16309a6a', 'url': 'https://github.com/dolphin-emu/dolphin/pull/14731#discussion_r3609162555', 'is_part_of_review': False, 'type': 'gh_pull_request_comment'}
2026-07-18T20:43:05.733340	{'source': 'ghhookparser', 'repo': 'dolphin-emu/dolphin', 'author': 'thethiny', 'action': 'created', 'id': 14731, 'hash': '81f336974c3eb2f93c05073734d2d7dc16309a6a', 'url': 'https://github.com/dolphin-emu/dolphin/pull/14731#discussion_r3609159791', 'is_part_of_review': False, 'type': 'gh_pull_request_comment'}
2026-07-18T06:37:38.102128	{'source': 'ghhookparser', 'repo': 'dolphin-emu/dolphin', 'author': 'phire', 'action': 'created', 'id': 14731, 'hash': '81f336974c3eb2f93c05073734d2d7dc16309a6a', 'url': 'https://github.com/dolphin-emu/dolphin/pull/14731#discussion_r3607799388', 'is_part_of_review': False, 'type': 'gh_pull_request_comment'}
2026-07-18T05:57:59.509664	{'source': 'ghhookparser', 'repo': 'dolphin-emu/dolphin', 'author': 'phire', 'action': 'created', 'id': 14731, 'hash': '81f336974c3eb2f93c05073734d2d7dc16309a6a', 'url': 'https://github.com/dolphin-emu/dolphin/pull/14731#discussion_r3607711355', 'is_part_of_review': True, 'type': 'gh_pull_request_comment'}
2026-07-18T05:57:59.402519	{'source': 'ghhookparser', 'repo': 'dolphin-emu/dolphin', 'author': 'phire', 'action': 'created', 'id': 14731, 'hash': '81f336974c3eb2f93c05073734d2d7dc16309a6a', 'url': 'https://github.com/dolphin-emu/dolphin/pull/14731#discussion_r3607686059', 'is_part_of_review': True, 'type': 'gh_pull_request_comment'}
2026-07-18T05:57:59.368649	{'source': 'ghhookparser', 'repo': 'dolphin-emu/dolphin', 'author': 'phire', 'action': 'created', 'id': 14731, 'hash': '81f336974c3eb2f93c05073734d2d7dc16309a6a', 'url': 'https://github.com/dolphin-emu/dolphin/pull/14731#discussion_r3607715133', 'is_part_of_review': True, 'type': 'gh_pull_request_comment'}
2026-07-18T05:57:59.368045	{'source': 'ghhookparser', 'repo': 'dolphin-emu/dolphin', 'author': 'phire', 'action': 'created', 'id': 14731, 'hash': '81f336974c3eb2f93c05073734d2d7dc16309a6a', 'url': 'https://github.com/dolphin-emu/dolphin/pull/14731#discussion_r3607739231', 'is_part_of_review': True, 'type': 'gh_pull_request_comment'}

Recent 'gh_pull_request_review' events

2026-07-18T23:41:29.022743	{'source': 'ghhookparser', 'repo': 'dolphin-emu/dolphin', 'author': 'phire', 'action': 'submitted', 'pr_id': 14731, 'pr_title': 'Convert To WBFS Support', 'state': 'commented', 'url': 'https://github.com/dolphin-emu/dolphin/pull/14731#pullrequestreview-4729506940', 'comments': [{'id': 3609425504, 'node_id': 'PRRC_kwDOALCn2M7XI3Zg', 'url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/comments/3609425504', 'pull_request_review_id': 4729506940, 'diff_hunk': '@@ -186,7 +380,304 @@ std::unique_ptr<WbfsFileReader> WbfsFileReader::Create(File::DirectIOFile file,\n   if (!reader->IsGood())\n     reader.reset();\n \n+  if (reader && reader->m_has_nkit_header)\n+    reader->ReadPartitionInfo();\n+\n   return reader;\n }\n \n+// Converts any disc image to WBFS with an NKit v2 header for lossless round-trips.\n+// Strips disc-level junk and partition-level junk (encrypted sectors whose decrypted\n+// content is zero or LFG padding), records a junk bitmap for reconstruction.\n+// See: https://github.com/dolphin-emu/dolphin/pull/14731\n+bool ConvertToWBFS(BlobReader* infile, const std::string& infile_path,\n+                   const std::string& outfile_path, const CompressCB& callback)\n+{\n+  ASSERT(infile->GetDataSizeType() == DataSizeType::Accurate ||\n+         infile->GetDataSizeType() == DataSizeType::UpperBound);\n+\n+  File::DirectIOFile outfile(outfile_path, File::AccessMode::Write);\n+  if (!outfile.IsOpen())\n+  {\n+    PanicAlertFmtT(\n+        "Failed to open the output file \\"{0}\\".\\n"\n+        "Check that you have permissions to write the target folder and that the media can "\n+        "be written.",\n+        outfile_path);\n+    return false;\n+  }\n+\n+  const u64 disc_size = infile->GetDataSize();\n+\n+  // These match the values used by standard WBFS tools (wwt, WBFS Manager)\n+  static constexpr u8 hd_sector_shift = 9;\n+  static constexpr u8 wbfs_sector_shift = 21;\n+  static constexpr u64 hd_sector_size = 1ull << hd_sector_shift;\n+  static constexpr u64 wbfs_sector_size = 1ull << wbfs_sector_shift;\n+\n+  const u64 blocks_per_disc = (disc_size + wbfs_sector_size - 1) / wbfs_sector_size;\n+  const u64 disc_info_size =\n+      Common::AlignUp(WII_DISC_HEADER_SIZE + blocks_per_disc * sizeof(u16), hd_sector_size);\n+\n+  // Read disc header (first 256 bytes contain disc_id, disc_num, title, etc.)\n+  std::vector<u8> disc_header(WII_DISC_HEADER_SIZE, 0);\n+  if (!infile->Read(0, WII_DISC_HEADER_SIZE, disc_header.data()))\n+  {\n+    PanicAlertFmtT("Failed to read from the input file \\"{0}\\".", infile_path);\n+    return false;\n+  }\n+\n+  // Use Volume for partition info and decrypted reads\n+  struct PartitionInfo\n+  {\n+    u64 data_offset;\n+    u64 data_size;\n+    Partition partition;\n+  };\n+  std::vector<PartitionInfo> partitions;\n+\n+  std::unique_ptr<VolumeDisc> volume = CreateDisc(infile_path);\n+  if (volume)\n+  {\n+    for (const Partition& partition : volume->GetPartitions())\n+    {\n+      const std::optional<u64> data_offset =\n+          volume->ReadSwappedAndShifted(partition.offset + 0x2B8, PARTITION_NONE);\n+      const std::optional<u64> data_size =\n+          volume->ReadSwappedAndShifted(partition.offset + 0x2BC, PARTITION_NONE);\n+      if (!data_offset || !data_size)\n+        continue;\n+\n+      PartitionInfo info;\n+      info.data_offset = partition.offset + *data_offset;\n+      info.data_size = *data_size;\n+      info.partition = partition;\n+      partitions.push_back(info);\n+    }\n+  }\n+\n+  // NKit v2 gap type bitmap: 1 bit per block, MSB-first, always sized for dual-layer\n+  const u64 gap_type_blocks = (DL_DVD_SIZE + wbfs_sector_size - 1) / wbfs_sector_size;\n+  const u64 gap_type_bytes = (gap_type_blocks + 7) / 8;\n+  std::vector<u8> gap_type(gap_type_bytes, 0);\n+\n+  // Compute data_start up front so we can write sectors during the scan\n+  const u64 data_start = Common::AlignUp(hd_sector_size + disc_info_size, wbfs_sector_size);\n+  const u16 wlba_base = static_cast<u16>(data_start / wbfs_sector_size);\n+\n+  // Single pass: scan, classify, hash, and write used sectors in one loop\n+  std::vector<u8> sector_buf(wbfs_sector_size, 0);\n+  std::vector<u16> wlba_table(blocks_per_disc, 0);\n+  u16 used_count = 0;\n+\n+  // NKit v2 stores four hash digests for verification\n+  auto sha1_ctx = Common::SHA1::CreateContext();\n+  u32 crc = Common::StartCRC32();\n+  mbedtls_md5_context md5_ctx{};\n+  mbedtls_md5_init(&md5_ctx);\n+  mbedtls_md5_starts_ret(&md5_ctx);\n+  XXH64_state_t* xxh_state = XXH64_createState();\n+  XXH64_reset(xxh_state, 0);\n+\n+  for (u64 i = 0; i < blocks_per_disc; i++)\n+  {\n+    if (i % 100 == 0)\n+    {\n+      const bool was_cancelled =\n+          !callback(Common::GetStringT("Converting"),\n+                    static_cast<float>(i) / static_cast<float>(blocks_per_disc));\n+      if (was_cancelled)\n+      {\n+        XXH64_freeState(xxh_state);\n+        mbedtls_md5_free(&md5_ctx);\n+        outfile.Close();\n+        File::Delete(outfile_path);\n+        return false;\n+      }\n+    }\n+\n+    const u64 offset = i * wbfs_sector_size;\n+    const size_t sz = static_cast<size_t>(std::min(wbfs_sector_size, disc_size - offset));\n+\n+    if (!infile->Read(offset, sz, sector_buf.data()))', 'path': 'Source/Core/DiscIO/WbfsBlob.cpp', 'position': 409, 'original_position': 409, 'commit_id': '24b41d58df2315831b74f76b95417f2739d02f9d', 'user': {'login': 'phire', 'id': 138484, 'node_id': 'MDQ6VXNlcjEzODQ4NA==', 'avatar_url': 'https://avatars.githubusercontent.com/u/138484?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/phire', 'html_url': 'https://github.com/phire', 'followers_url': 'https://api.github.com/users/phire/followers', 'following_url': 'https://api.github.com/users/phire/following{/other_user}', 'gists_url': 'https://api.github.com/users/phire/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/phire/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/phire/subscriptions', 'organizations_url': 'https://api.github.com/users/phire/orgs', 'repos_url': 'https://api.github.com/users/phire/repos', 'events_url': 'https://api.github.com/users/phire/events{/privacy}', 'received_events_url': 'https://api.github.com/users/phire/received_events', 'type': 'User', 'user_view_type': 'public', 'site_admin': False}, 'body': 'Oh... I forgot about the digests. Guess we do need it. ', 'created_at': '2026-07-18T23:41:27Z', 'updated_at': '2026-07-18T23:41:27Z', 'html_url': 'https://github.com/dolphin-emu/dolphin/pull/14731#discussion_r3609425504', 'pull_request_url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/14731', 'author_association': 'MEMBER', '_links': {'self': {'href': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/comments/3609425504'}, 'html': {'href': 'https://github.com/dolphin-emu/dolphin/pull/14731#discussion_r3609425504'}, 'pull_request': {'href': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/14731'}}, 'original_commit_id': '24b41d58df2315831b74f76b95417f2739d02f9d', 'reactions': {'url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/comments/3609425504/reactions', 'total_count': 0, '+1': 0, '-1': 0, 'laugh': 0, 'hooray': 0, 'confused': 0, 'heart': 0, 'rocket': 0, 'eyes': 0}, 'in_reply_to_id': 3609251889}], 'type': 'gh_pull_request_review'}
2026-07-18T23:37:37.379700	{'source': 'ghhookparser', 'repo': 'dolphin-emu/dolphin', 'author': 'thethiny', 'action': 'submitted', 'pr_id': 14731, 'pr_title': 'Convert To WBFS Support', 'state': 'commented', 'url': 'https://github.com/dolphin-emu/dolphin/pull/14731#pullrequestreview-4729501733', 'comments': [{'id': 3609419546, 'node_id': 'PRRC_kwDOALCn2M7XI18a', 'url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/comments/3609419546', 'pull_request_review_id': 4729501733, 'diff_hunk': '@@ -186,7 +380,304 @@ std::unique_ptr<WbfsFileReader> WbfsFileReader::Create(File::DirectIOFile file,\n   if (!reader->IsGood())\n     reader.reset();\n \n+  if (reader && reader->m_has_nkit_header)\n+    reader->ReadPartitionInfo();\n+\n   return reader;\n }\n \n+// Converts any disc image to WBFS with an NKit v2 header for lossless round-trips.\n+// Strips disc-level junk and partition-level junk (encrypted sectors whose decrypted\n+// content is zero or LFG padding), records a junk bitmap for reconstruction.\n+// See: https://github.com/dolphin-emu/dolphin/pull/14731\n+bool ConvertToWBFS(BlobReader* infile, const std::string& infile_path,\n+                   const std::string& outfile_path, const CompressCB& callback)\n+{\n+  ASSERT(infile->GetDataSizeType() == DataSizeType::Accurate ||\n+         infile->GetDataSizeType() == DataSizeType::UpperBound);\n+\n+  File::DirectIOFile outfile(outfile_path, File::AccessMode::Write);\n+  if (!outfile.IsOpen())\n+  {\n+    PanicAlertFmtT(\n+        "Failed to open the output file \\"{0}\\".\\n"\n+        "Check that you have permissions to write the target folder and that the media can "\n+        "be written.",\n+        outfile_path);\n+    return false;\n+  }\n+\n+  const u64 disc_size = infile->GetDataSize();\n+\n+  // These match the values used by standard WBFS tools (wwt, WBFS Manager)\n+  static constexpr u8 hd_sector_shift = 9;\n+  static constexpr u8 wbfs_sector_shift = 21;\n+  static constexpr u64 hd_sector_size = 1ull << hd_sector_shift;\n+  static constexpr u64 wbfs_sector_size = 1ull << wbfs_sector_shift;\n+\n+  const u64 blocks_per_disc = (disc_size + wbfs_sector_size - 1) / wbfs_sector_size;\n+  const u64 disc_info_size =\n+      Common::AlignUp(WII_DISC_HEADER_SIZE + blocks_per_disc * sizeof(u16), hd_sector_size);\n+\n+  // Read disc header (first 256 bytes contain disc_id, disc_num, title, etc.)\n+  std::vector<u8> disc_header(WII_DISC_HEADER_SIZE, 0);\n+  if (!infile->Read(0, WII_DISC_HEADER_SIZE, disc_header.data()))\n+  {\n+    PanicAlertFmtT("Failed to read from the input file \\"{0}\\".", infile_path);\n+    return false;\n+  }\n+\n+  // Use Volume for partition info and decrypted reads\n+  struct PartitionInfo\n+  {\n+    u64 data_offset;\n+    u64 data_size;\n+    Partition partition;\n+  };\n+  std::vector<PartitionInfo> partitions;\n+\n+  std::unique_ptr<VolumeDisc> volume = CreateDisc(infile_path);\n+  if (volume)\n+  {\n+    for (const Partition& partition : volume->GetPartitions())\n+    {\n+      const std::optional<u64> data_offset =\n+          volume->ReadSwappedAndShifted(partition.offset + 0x2B8, PARTITION_NONE);\n+      const std::optional<u64> data_size =\n+          volume->ReadSwappedAndShifted(partition.offset + 0x2BC, PARTITION_NONE);\n+      if (!data_offset || !data_size)\n+        continue;\n+\n+      PartitionInfo info;\n+      info.data_offset = partition.offset + *data_offset;\n+      info.data_size = *data_size;\n+      info.partition = partition;\n+      partitions.push_back(info);\n+    }\n+  }\n+\n+  // NKit v2 gap type bitmap: 1 bit per block, MSB-first, always sized for dual-layer\n+  const u64 gap_type_blocks = (DL_DVD_SIZE + wbfs_sector_size - 1) / wbfs_sector_size;\n+  const u64 gap_type_bytes = (gap_type_blocks + 7) / 8;\n+  std::vector<u8> gap_type(gap_type_bytes, 0);\n+\n+  // Compute data_start up front so we can write sectors during the scan\n+  const u64 data_start = Common::AlignUp(hd_sector_size + disc_info_size, wbfs_sector_size);\n+  const u16 wlba_base = static_cast<u16>(data_start / wbfs_sector_size);\n+\n+  // Single pass: scan, classify, hash, and write used sectors in one loop\n+  std::vector<u8> sector_buf(wbfs_sector_size, 0);\n+  std::vector<u16> wlba_table(blocks_per_disc, 0);\n+  u16 used_count = 0;\n+\n+  // NKit v2 stores four hash digests for verification\n+  auto sha1_ctx = Common::SHA1::CreateContext();\n+  u32 crc = Common::StartCRC32();\n+  mbedtls_md5_context md5_ctx{};\n+  mbedtls_md5_init(&md5_ctx);\n+  mbedtls_md5_starts_ret(&md5_ctx);\n+  XXH64_state_t* xxh_state = XXH64_createState();\n+  XXH64_reset(xxh_state, 0);\n+\n+  for (u64 i = 0; i < blocks_per_disc; i++)\n+  {\n+    if (i % 100 == 0)\n+    {\n+      const bool was_cancelled =\n+          !callback(Common::GetStringT("Converting"),\n+                    static_cast<float>(i) / static_cast<float>(blocks_per_disc));\n+      if (was_cancelled)\n+      {\n+        XXH64_freeState(xxh_state);\n+        mbedtls_md5_free(&md5_ctx);\n+        outfile.Close();\n+        File::Delete(outfile_path);\n+        return false;\n+      }\n+    }\n+\n+    const u64 offset = i * wbfs_sector_size;\n+    const size_t sz = static_cast<size_t>(std::min(wbfs_sector_size, disc_size - offset));\n+\n+    if (!infile->Read(offset, sz, sector_buf.data()))\n+    {\n+      PanicAlertFmtT("Failed to read from the input file \\"{0}\\".", infile_path);\n+      XXH64_freeState(xxh_state);\n+      mbedtls_md5_free(&md5_ctx);\n+      outfile.Close();\n+      File::Delete(outfile_path);\n+      return false;\n+    }\n+\n+    // Update all four hashes with the full disc data\n+    sha1_ctx->Update(sector_buf.data(), sz);\n+    crc = Common::UpdateCRC32(crc, sector_buf.data(), sz);\n+    mbedtls_md5_update_ret(&md5_ctx, sector_buf.data(), sz);\n+    XXH64_update(xxh_state, sector_buf.data(), sz);\n+\n+    // Find which partition (if any) this block belongs to\n+    const u32 start_sector = static_cast<u32>(offset / VolumeWii::BLOCK_TOTAL_SIZE);\n+    const u32 end_sector = static_cast<u32>((offset + sz) / VolumeWii::BLOCK_TOTAL_SIZE);\n+    const auto it = std::ranges::find_if(partitions, [&](const PartitionInfo& p) {\n+      const u32 p_start = static_cast<u32>(p.data_offset / VolumeWii::BLOCK_TOTAL_SIZE);\n+      const u32 p_end =\n+          static_cast<u32>((p.data_offset + p.data_size) / VolumeWii::BLOCK_TOTAL_SIZE);', 'path': 'Source/Core/DiscIO/WbfsBlob.cpp', 'position': 431, 'original_position': 431, 'commit_id': '24b41d58df2315831b74f76b95417f2739d02f9d', 'user': {'login': 'thethiny', 'id': 6018214, 'node_id': 'MDQ6VXNlcjYwMTgyMTQ=', 'avatar_url': 'https://avatars.githubusercontent.com/u/6018214?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/thethiny', 'html_url': 'https://github.com/thethiny', 'followers_url': 'https://api.github.com/users/thethiny/followers', 'following_url': 'https://api.github.com/users/thethiny/following{/other_user}', 'gists_url': 'https://api.github.com/users/thethiny/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/thethiny/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/thethiny/subscriptions', 'organizations_url': 'https://api.github.com/users/thethiny/orgs', 'repos_url': 'https://api.github.com/users/thethiny/repos', 'events_url': 'https://api.github.com/users/thethiny/events{/privacy}', 'received_events_url': 'https://api.github.com/users/thethiny/received_events', 'type': 'User', 'user_view_type': 'public', 'site_admin': False}, 'body': 'this is an oversight on my end due to iterative coding. Noted', 'created_at': '2026-07-18T23:37:35Z', 'updated_at': '2026-07-18T23:37:35Z', 'html_url': 'https://github.com/dolphin-emu/dolphin/pull/14731#discussion_r3609419546', 'pull_request_url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/14731', 'author_association': 'NONE', '_links': {'self': {'href': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/comments/3609419546'}, 'html': {'href': 'https://github.com/dolphin-emu/dolphin/pull/14731#discussion_r3609419546'}, 'pull_request': {'href': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/14731'}}, 'original_commit_id': '24b41d58df2315831b74f76b95417f2739d02f9d', 'reactions': {'url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/comments/3609419546/reactions', 'total_count': 0, '+1': 0, '-1': 0, 'laugh': 0, 'hooray': 0, 'confused': 0, 'heart': 0, 'rocket': 0, 'eyes': 0}, 'in_reply_to_id': 3609363364}], 'type': 'gh_pull_request_review'}
2026-07-18T23:36:12.676066	{'source': 'ghhookparser', 'repo': 'dolphin-emu/dolphin', 'author': 'thethiny', 'action': 'submitted', 'pr_id': 14731, 'pr_title': 'Convert To WBFS Support', 'state': 'commented', 'url': 'https://github.com/dolphin-emu/dolphin/pull/14731#pullrequestreview-4729499717', 'comments': [{'id': 3609417157, 'node_id': 'PRRC_kwDOALCn2M7XI1XF', 'url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/comments/3609417157', 'pull_request_review_id': 4729499717, 'diff_hunk': '@@ -119,22 +144,191 @@ bool WbfsFileReader::ReadHeader()\n   return m_header.disc_table[0] != 0;\n }\n \n+bool WbfsFileReader::ReadNKitHeader()\n+{\n+  const u64 gap_type_blocks = (DL_DVD_SIZE + m_wbfs_sector_size - 1) / m_wbfs_sector_size;\n+  m_nkit_info = NKit::ReadHeaderFromFile(m_files[0].file, NKit::HEADER_OFFSET, gap_type_blocks);\n+  if (!m_nkit_info.valid)\n+    return false;\n+\n+  m_has_nkit_header = true;\n+  return true;\n+}\n+\n+bool WbfsFileReader::IsBlockStored(u64 block_index) const\n+{\n+  return block_index < m_blocks_per_disc && m_wlba_table[block_index] != 0;\n+}\n+\n+bool WbfsFileReader::IsGapJunk(u64 block_index) const\n+{\n+  return NKit::IsGapJunk(m_nkit_info.gap_type, block_index);\n+}\n+\n+void WbfsFileReader::GenerateJunkData(u64 disc_offset, u64 size, u8* out) const\n+{\n+  LaggedFibonacciGenerator::FillJunkData(out, static_cast<size_t>(size), disc_offset, m_disc_id,\n+                                         m_disc_num);\n+}\n+\n+void WbfsFileReader::ReadPartitionInfo()\n+{\n+  std::unique_ptr<VolumeDisc> volume = CreateDisc(CopyReader());\n+  if (!volume)\n+    return;\n+\n+  for (const Partition& partition : volume->GetPartitions())\n+  {\n+    const auto& ticket = volume->GetTicket(partition);\n+    const std::array<u8, 16> title_key = ticket.GetTitleKey();\n+\n+    u8 data_info[8];\n+    if (!Read(partition.offset + 0x2B8, 8, data_info))\n+      continue;\n+\n+    PartitionEntry entry;\n+    entry.data_offset = partition.offset + (static_cast<u64>(Common::swap32(data_info)) << 2);\n+    entry.data_size = static_cast<u64>(Common::swap32(data_info + 4)) << 2;\n+    entry.key = title_key;\n+    m_partitions.push_back(entry);\n+  }\n+}\n+\n+const WbfsFileReader::PartitionEntry* WbfsFileReader::FindPartition(u64 disc_offset) const\n+{\n+  for (const auto& p : m_partitions)\n+  {\n+    if (disc_offset >= p.data_offset && disc_offset < p.data_offset + p.data_size)\n+      return &p;\n+  }\n+  return nullptr;\n+}\n+\n+const WbfsFileReader::PartitionEntry*\n+WbfsFileReader::FindPartitionByDataOffset(u64 partition_data_offset) const\n+{\n+  for (const auto& p : m_partitions)\n+  {\n+    if (p.data_offset == partition_data_offset)\n+      return &p;\n+  }\n+  return nullptr;\n+}\n+\n+bool WbfsFileReader::SupportsReadWiiDecrypted(u64 offset, u64 size, u64 partition_data_offset) const\n+{\n+  if (!m_has_nkit_header)\n+    return false;\n+\n+  const u64 block_in_partition = offset / VolumeWii::BLOCK_DATA_SIZE;\n+  const u64 disc_offset = partition_data_offset + block_in_partition * VolumeWii::BLOCK_TOTAL_SIZE;\n+  const u64 wbfs_block = disc_offset >> m_header.wbfs_sector_shift;\n+\n+  return wbfs_block < m_blocks_per_disc && !IsBlockStored(wbfs_block);\n+}\n+\n+bool WbfsFileReader::ReadWiiDecrypted(u64 offset, u64 size, u8* out_ptr, u64 partition_data_offset)\n+{\n+  const PartitionEntry* pe = FindPartitionByDataOffset(partition_data_offset);\n+  if (!pe)\n+    return false;\n+\n+  auto aes_ctx = Common::AES::CreateContextDecrypt(pe->key.data());\n+  std::vector<u8> encrypted(VolumeWii::BLOCK_TOTAL_SIZE);\n+  std::vector<u8> decrypted(VolumeWii::BLOCK_DATA_SIZE);\n+\n+  while (size > 0)\n+  {\n+    const u64 block_in_partition = offset / VolumeWii::BLOCK_DATA_SIZE;\n+    const u64 offset_in_block = offset % VolumeWii::BLOCK_DATA_SIZE;\n+    const u64 bytes_in_block = VolumeWii::BLOCK_DATA_SIZE - offset_in_block;\n+    const size_t read_size = static_cast<size_t>(std::min(bytes_in_block, size));\n+\n+    const u64 disc_offset =\n+        partition_data_offset + block_in_partition * VolumeWii::BLOCK_TOTAL_SIZE;\n+    const u64 wbfs_block = disc_offset >> m_header.wbfs_sector_shift;\n+\n+    if (IsBlockStored(wbfs_block))\n+    {\n+      u64 available;\n+      auto& file = SeekToCluster(disc_offset, &available);\n+      if (available < VolumeWii::BLOCK_TOTAL_SIZE ||\n+          !file.Read(encrypted.data(), VolumeWii::BLOCK_TOTAL_SIZE))\n+        return false;\n+      VolumeWii::DecryptBlockData(encrypted.data(), decrypted.data(), aes_ctx.get());\n+      std::memcpy(out_ptr, decrypted.data() + offset_in_block, read_size);\n+    }', 'path': 'Source/Core/DiscIO/WbfsBlob.cpp', 'position': 204, 'original_position': 204, 'commit_id': '24b41d58df2315831b74f76b95417f2739d02f9d', 'user': {'login': 'thethiny', 'id': 6018214, 'node_id': 'MDQ6VXNlcjYwMTgyMTQ=', 'avatar_url': 'https://avatars.githubusercontent.com/u/6018214?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/thethiny', 'html_url': 'https://github.com/thethiny', 'followers_url': 'https://api.github.com/users/thethiny/followers', 'following_url': 'https://api.github.com/users/thethiny/following{/other_user}', 'gists_url': 'https://api.github.com/users/thethiny/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/thethiny/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/thethiny/subscriptions', 'organizations_url': 'https://api.github.com/users/thethiny/orgs', 'repos_url': 'https://api.github.com/users/thethiny/repos', 'events_url': 'https://api.github.com/users/thethiny/events{/privacy}', 'received_events_url': 'https://api.github.com/users/thethiny/received_events', 'type': 'User', 'user_view_type': 'public', 'site_admin': False}, 'body': 'This needs an investigation, since EncryptGroup processes about 64 sectors and therefore the sectors could be a mix of stored and non-stored blocks. It is possible that this path will never hit but I cannot confirm that since I did not test it out. I will do so and report back with either a fix or a result.', 'created_at': '2026-07-18T23:36:11Z', 'updated_at': '2026-07-18T23:36:11Z', 'html_url': 'https://github.com/dolphin-emu/dolphin/pull/14731#discussion_r3609417157', 'pull_request_url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/14731', 'author_association': 'NONE', '_links': {'self': {'href': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/comments/3609417157'}, 'html': {'href': 'https://github.com/dolphin-emu/dolphin/pull/14731#discussion_r3609417157'}, 'pull_request': {'href': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/14731'}}, 'original_commit_id': '24b41d58df2315831b74f76b95417f2739d02f9d', 'reactions': {'url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/comments/3609417157/reactions', 'total_count': 0, '+1': 0, '-1': 0, 'laugh': 0, 'hooray': 0, 'confused': 0, 'heart': 0, 'rocket': 0, 'eyes': 0}, 'in_reply_to_id': 3609277919}], 'type': 'gh_pull_request_review'}
2026-07-18T23:33:15.219124	{'source': 'ghhookparser', 'repo': 'dolphin-emu/dolphin', 'author': 'thethiny', 'action': 'submitted', 'pr_id': 14731, 'pr_title': 'Convert To WBFS Support', 'state': 'commented', 'url': 'https://github.com/dolphin-emu/dolphin/pull/14731#pullrequestreview-4729496492', 'comments': [{'id': 3609413351, 'node_id': 'PRRC_kwDOALCn2M7XI0bn', 'url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/comments/3609413351', 'pull_request_review_id': 4729496492, 'diff_hunk': '@@ -186,7 +380,304 @@ std::unique_ptr<WbfsFileReader> WbfsFileReader::Create(File::DirectIOFile file,\n   if (!reader->IsGood())\n     reader.reset();\n \n+  if (reader && reader->m_has_nkit_header)\n+    reader->ReadPartitionInfo();\n+\n   return reader;\n }\n \n+// Converts any disc image to WBFS with an NKit v2 header for lossless round-trips.\n+// Strips disc-level junk and partition-level junk (encrypted sectors whose decrypted\n+// content is zero or LFG padding), records a junk bitmap for reconstruction.\n+// See: https://github.com/dolphin-emu/dolphin/pull/14731\n+bool ConvertToWBFS(BlobReader* infile, const std::string& infile_path,\n+                   const std::string& outfile_path, const CompressCB& callback)\n+{\n+  ASSERT(infile->GetDataSizeType() == DataSizeType::Accurate ||\n+         infile->GetDataSizeType() == DataSizeType::UpperBound);\n+\n+  File::DirectIOFile outfile(outfile_path, File::AccessMode::Write);\n+  if (!outfile.IsOpen())\n+  {\n+    PanicAlertFmtT(\n+        "Failed to open the output file \\"{0}\\".\\n"\n+        "Check that you have permissions to write the target folder and that the media can "\n+        "be written.",\n+        outfile_path);\n+    return false;\n+  }\n+\n+  const u64 disc_size = infile->GetDataSize();\n+\n+  // These match the values used by standard WBFS tools (wwt, WBFS Manager)\n+  static constexpr u8 hd_sector_shift = 9;\n+  static constexpr u8 wbfs_sector_shift = 21;\n+  static constexpr u64 hd_sector_size = 1ull << hd_sector_shift;\n+  static constexpr u64 wbfs_sector_size = 1ull << wbfs_sector_shift;\n+\n+  const u64 blocks_per_disc = (disc_size + wbfs_sector_size - 1) / wbfs_sector_size;\n+  const u64 disc_info_size =\n+      Common::AlignUp(WII_DISC_HEADER_SIZE + blocks_per_disc * sizeof(u16), hd_sector_size);\n+\n+  // Read disc header (first 256 bytes contain disc_id, disc_num, title, etc.)\n+  std::vector<u8> disc_header(WII_DISC_HEADER_SIZE, 0);\n+  if (!infile->Read(0, WII_DISC_HEADER_SIZE, disc_header.data()))\n+  {\n+    PanicAlertFmtT("Failed to read from the input file \\"{0}\\".", infile_path);\n+    return false;\n+  }\n+\n+  // Use Volume for partition info and decrypted reads\n+  struct PartitionInfo\n+  {\n+    u64 data_offset;\n+    u64 data_size;\n+    Partition partition;\n+  };\n+  std::vector<PartitionInfo> partitions;\n+\n+  std::unique_ptr<VolumeDisc> volume = CreateDisc(infile_path);\n+  if (volume)\n+  {\n+    for (const Partition& partition : volume->GetPartitions())\n+    {\n+      const std::optional<u64> data_offset =\n+          volume->ReadSwappedAndShifted(partition.offset + 0x2B8, PARTITION_NONE);\n+      const std::optional<u64> data_size =\n+          volume->ReadSwappedAndShifted(partition.offset + 0x2BC, PARTITION_NONE);\n+      if (!data_offset || !data_size)\n+        continue;\n+\n+      PartitionInfo info;\n+      info.data_offset = partition.offset + *data_offset;\n+      info.data_size = *data_size;\n+      info.partition = partition;\n+      partitions.push_back(info);\n+    }\n+  }\n+\n+  // NKit v2 gap type bitmap: 1 bit per block, MSB-first, always sized for dual-layer\n+  const u64 gap_type_blocks = (DL_DVD_SIZE + wbfs_sector_size - 1) / wbfs_sector_size;\n+  const u64 gap_type_bytes = (gap_type_blocks + 7) / 8;\n+  std::vector<u8> gap_type(gap_type_bytes, 0);\n+\n+  // Compute data_start up front so we can write sectors during the scan\n+  const u64 data_start = Common::AlignUp(hd_sector_size + disc_info_size, wbfs_sector_size);\n+  const u16 wlba_base = static_cast<u16>(data_start / wbfs_sector_size);\n+\n+  // Single pass: scan, classify, hash, and write used sectors in one loop\n+  std::vector<u8> sector_buf(wbfs_sector_size, 0);\n+  std::vector<u16> wlba_table(blocks_per_disc, 0);\n+  u16 used_count = 0;\n+\n+  // NKit v2 stores four hash digests for verification\n+  auto sha1_ctx = Common::SHA1::CreateContext();\n+  u32 crc = Common::StartCRC32();\n+  mbedtls_md5_context md5_ctx{};\n+  mbedtls_md5_init(&md5_ctx);\n+  mbedtls_md5_starts_ret(&md5_ctx);\n+  XXH64_state_t* xxh_state = XXH64_createState();\n+  XXH64_reset(xxh_state, 0);\n+\n+  for (u64 i = 0; i < blocks_per_disc; i++)\n+  {\n+    if (i % 100 == 0)\n+    {\n+      const bool was_cancelled =\n+          !callback(Common::GetStringT("Converting"),\n+                    static_cast<float>(i) / static_cast<float>(blocks_per_disc));\n+      if (was_cancelled)\n+      {\n+        XXH64_freeState(xxh_state);\n+        mbedtls_md5_free(&md5_ctx);\n+        outfile.Close();\n+        File::Delete(outfile_path);', 'path': 'Source/Core/DiscIO/WbfsBlob.cpp', 'position': 401, 'original_position': 401, 'commit_id': '24b41d58df2315831b74f76b95417f2739d02f9d', 'user': {'login': 'thethiny', 'id': 6018214, 'node_id': 'MDQ6VXNlcjYwMTgyMTQ=', 'avatar_url': 'https://avatars.githubusercontent.com/u/6018214?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/thethiny', 'html_url': 'https://github.com/thethiny', 'followers_url': 'https://api.github.com/users/thethiny/followers', 'following_url': 'https://api.github.com/users/thethiny/following{/other_user}', 'gists_url': 'https://api.github.com/users/thethiny/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/thethiny/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/thethiny/subscriptions', 'organizations_url': 'https://api.github.com/users/thethiny/orgs', 'repos_url': 'https://api.github.com/users/thethiny/repos', 'events_url': 'https://api.github.com/users/thethiny/events{/privacy}', 'received_events_url': 'https://api.github.com/users/thethiny/received_events', 'type': 'User', 'user_view_type': 'public', 'site_admin': False}, 'body': 'I was unaware of the concept of Scope Guards and RAII, thank you for this!', 'created_at': '2026-07-18T23:33:13Z', 'updated_at': '2026-07-18T23:33:13Z', 'html_url': 'https://github.com/dolphin-emu/dolphin/pull/14731#discussion_r3609413351', 'pull_request_url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/14731', 'author_association': 'NONE', '_links': {'self': {'href': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/comments/3609413351'}, 'html': {'href': 'https://github.com/dolphin-emu/dolphin/pull/14731#discussion_r3609413351'}, 'pull_request': {'href': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/14731'}}, 'original_commit_id': '24b41d58df2315831b74f76b95417f2739d02f9d', 'reactions': {'url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/comments/3609413351/reactions', 'total_count': 0, '+1': 0, '-1': 0, 'laugh': 0, 'hooray': 0, 'confused': 0, 'heart': 0, 'rocket': 0, 'eyes': 0}, 'in_reply_to_id': 3609268698}], 'type': 'gh_pull_request_review'}
2026-07-18T23:29:02.352465	{'source': 'ghhookparser', 'repo': 'dolphin-emu/dolphin', 'author': 'thethiny', 'action': 'submitted', 'pr_id': 14731, 'pr_title': 'Convert To WBFS Support', 'state': 'commented', 'url': 'https://github.com/dolphin-emu/dolphin/pull/14731#pullrequestreview-4729491883', 'comments': [{'id': 3609408071, 'node_id': 'PRRC_kwDOALCn2M7XIzJH', 'url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/comments/3609408071', 'pull_request_review_id': 4729491883, 'diff_hunk': '@@ -186,7 +380,304 @@ std::unique_ptr<WbfsFileReader> WbfsFileReader::Create(File::DirectIOFile file,\n   if (!reader->IsGood())\n     reader.reset();\n \n+  if (reader && reader->m_has_nkit_header)\n+    reader->ReadPartitionInfo();\n+\n   return reader;\n }\n \n+// Converts any disc image to WBFS with an NKit v2 header for lossless round-trips.\n+// Strips disc-level junk and partition-level junk (encrypted sectors whose decrypted\n+// content is zero or LFG padding), records a junk bitmap for reconstruction.\n+// See: https://github.com/dolphin-emu/dolphin/pull/14731\n+bool ConvertToWBFS(BlobReader* infile, const std::string& infile_path,\n+                   const std::string& outfile_path, const CompressCB& callback)\n+{\n+  ASSERT(infile->GetDataSizeType() == DataSizeType::Accurate ||\n+         infile->GetDataSizeType() == DataSizeType::UpperBound);\n+\n+  File::DirectIOFile outfile(outfile_path, File::AccessMode::Write);\n+  if (!outfile.IsOpen())\n+  {\n+    PanicAlertFmtT(\n+        "Failed to open the output file \\"{0}\\".\\n"\n+        "Check that you have permissions to write the target folder and that the media can "\n+        "be written.",\n+        outfile_path);\n+    return false;\n+  }\n+\n+  const u64 disc_size = infile->GetDataSize();\n+\n+  // These match the values used by standard WBFS tools (wwt, WBFS Manager)\n+  static constexpr u8 hd_sector_shift = 9;\n+  static constexpr u8 wbfs_sector_shift = 21;\n+  static constexpr u64 hd_sector_size = 1ull << hd_sector_shift;\n+  static constexpr u64 wbfs_sector_size = 1ull << wbfs_sector_shift;\n+\n+  const u64 blocks_per_disc = (disc_size + wbfs_sector_size - 1) / wbfs_sector_size;\n+  const u64 disc_info_size =\n+      Common::AlignUp(WII_DISC_HEADER_SIZE + blocks_per_disc * sizeof(u16), hd_sector_size);\n+\n+  // Read disc header (first 256 bytes contain disc_id, disc_num, title, etc.)\n+  std::vector<u8> disc_header(WII_DISC_HEADER_SIZE, 0);\n+  if (!infile->Read(0, WII_DISC_HEADER_SIZE, disc_header.data()))\n+  {\n+    PanicAlertFmtT("Failed to read from the input file \\"{0}\\".", infile_path);\n+    return false;\n+  }\n+\n+  // Use Volume for partition info and decrypted reads\n+  struct PartitionInfo\n+  {\n+    u64 data_offset;\n+    u64 data_size;\n+    Partition partition;\n+  };\n+  std::vector<PartitionInfo> partitions;\n+\n+  std::unique_ptr<VolumeDisc> volume = CreateDisc(infile_path);\n+  if (volume)\n+  {\n+    for (const Partition& partition : volume->GetPartitions())\n+    {\n+      const std::optional<u64> data_offset =\n+          volume->ReadSwappedAndShifted(partition.offset + 0x2B8, PARTITION_NONE);\n+      const std::optional<u64> data_size =\n+          volume->ReadSwappedAndShifted(partition.offset + 0x2BC, PARTITION_NONE);\n+      if (!data_offset || !data_size)\n+        continue;\n+\n+      PartitionInfo info;\n+      info.data_offset = partition.offset + *data_offset;\n+      info.data_size = *data_size;\n+      info.partition = partition;\n+      partitions.push_back(info);\n+    }\n+  }\n+\n+  // NKit v2 gap type bitmap: 1 bit per block, MSB-first, always sized for dual-layer\n+  const u64 gap_type_blocks = (DL_DVD_SIZE + wbfs_sector_size - 1) / wbfs_sector_size;\n+  const u64 gap_type_bytes = (gap_type_blocks + 7) / 8;\n+  std::vector<u8> gap_type(gap_type_bytes, 0);\n+\n+  // Compute data_start up front so we can write sectors during the scan\n+  const u64 data_start = Common::AlignUp(hd_sector_size + disc_info_size, wbfs_sector_size);\n+  const u16 wlba_base = static_cast<u16>(data_start / wbfs_sector_size);\n+\n+  // Single pass: scan, classify, hash, and write used sectors in one loop\n+  std::vector<u8> sector_buf(wbfs_sector_size, 0);\n+  std::vector<u16> wlba_table(blocks_per_disc, 0);\n+  u16 used_count = 0;\n+\n+  // NKit v2 stores four hash digests for verification\n+  auto sha1_ctx = Common::SHA1::CreateContext();\n+  u32 crc = Common::StartCRC32();\n+  mbedtls_md5_context md5_ctx{};\n+  mbedtls_md5_init(&md5_ctx);\n+  mbedtls_md5_starts_ret(&md5_ctx);\n+  XXH64_state_t* xxh_state = XXH64_createState();\n+  XXH64_reset(xxh_state, 0);\n+\n+  for (u64 i = 0; i < blocks_per_disc; i++)\n+  {\n+    if (i % 100 == 0)\n+    {\n+      const bool was_cancelled =\n+          !callback(Common::GetStringT("Converting"),\n+                    static_cast<float>(i) / static_cast<float>(blocks_per_disc));\n+      if (was_cancelled)\n+      {\n+        XXH64_freeState(xxh_state);\n+        mbedtls_md5_free(&md5_ctx);\n+        outfile.Close();\n+        File::Delete(outfile_path);\n+        return false;\n+      }\n+    }\n+\n+    const u64 offset = i * wbfs_sector_size;\n+    const size_t sz = static_cast<size_t>(std::min(wbfs_sector_size, disc_size - offset));\n+\n+    if (!infile->Read(offset, sz, sector_buf.data()))', 'path': 'Source/Core/DiscIO/WbfsBlob.cpp', 'position': 409, 'original_position': 409, 'commit_id': '24b41d58df2315831b74f76b95417f2739d02f9d', 'user': {'login': 'thethiny', 'id': 6018214, 'node_id': 'MDQ6VXNlcjYwMTgyMTQ=', 'avatar_url': 'https://avatars.githubusercontent.com/u/6018214?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/thethiny', 'html_url': 'https://github.com/thethiny', 'followers_url': 'https://api.github.com/users/thethiny/followers', 'following_url': 'https://api.github.com/users/thethiny/following{/other_user}', 'gists_url': 'https://api.github.com/users/thethiny/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/thethiny/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/thethiny/subscriptions', 'organizations_url': 'https://api.github.com/users/thethiny/orgs', 'repos_url': 'https://api.github.com/users/thethiny/repos', 'events_url': 'https://api.github.com/users/thethiny/events{/privacy}', 'received_events_url': 'https://api.github.com/users/thethiny/received_events', 'type': 'User', 'user_view_type': 'public', 'site_admin': False}, 'body': 'We can defer the read for classification, but the NKit digests need the raw encrypted bytes for every sector including junk. How should we handle hashing for sectors we skip reading? Should hashing be its own pass separate from this?', 'created_at': '2026-07-18T23:29:00Z', 'updated_at': '2026-07-18T23:29:00Z', 'html_url': 'https://github.com/dolphin-emu/dolphin/pull/14731#discussion_r3609408071', 'pull_request_url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/14731', 'author_association': 'NONE', '_links': {'self': {'href': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/comments/3609408071'}, 'html': {'href': 'https://github.com/dolphin-emu/dolphin/pull/14731#discussion_r3609408071'}, 'pull_request': {'href': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/14731'}}, 'original_commit_id': '24b41d58df2315831b74f76b95417f2739d02f9d', 'reactions': {'url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/comments/3609408071/reactions', 'total_count': 0, '+1': 0, '-1': 0, 'laugh': 0, 'hooray': 0, 'confused': 0, 'heart': 0, 'rocket': 0, 'eyes': 0}, 'in_reply_to_id': 3609251889}], 'type': 'gh_pull_request_review'}
2026-07-18T23:14:47.908812	{'source': 'ghhookparser', 'repo': 'dolphin-emu/dolphin', 'author': 'phire', 'action': 'submitted', 'pr_id': 14731, 'pr_title': 'Convert To WBFS Support', 'state': 'commented', 'url': 'https://github.com/dolphin-emu/dolphin/pull/14731#pullrequestreview-4729467027', 'comments': [{'id': 3609382108, 'node_id': 'PRRC_kwDOALCn2M7XIszc', 'url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/comments/3609382108', 'pull_request_review_id': 4729467027, 'diff_hunk': '@@ -186,7 +380,304 @@ std::unique_ptr<WbfsFileReader> WbfsFileReader::Create(File::DirectIOFile file,\n   if (!reader->IsGood())\n     reader.reset();\n \n+  if (reader && reader->m_has_nkit_header)\n+    reader->ReadPartitionInfo();\n+\n   return reader;\n }\n \n+// Converts any disc image to WBFS with an NKit v2 header for lossless round-trips.\n+// Strips disc-level junk and partition-level junk (encrypted sectors whose decrypted\n+// content is zero or LFG padding), records a junk bitmap for reconstruction.\n+// See: https://github.com/dolphin-emu/dolphin/pull/14731\n+bool ConvertToWBFS(BlobReader* infile, const std::string& infile_path,\n+                   const std::string& outfile_path, const CompressCB& callback)\n+{\n+  ASSERT(infile->GetDataSizeType() == DataSizeType::Accurate ||\n+         infile->GetDataSizeType() == DataSizeType::UpperBound);\n+\n+  File::DirectIOFile outfile(outfile_path, File::AccessMode::Write);\n+  if (!outfile.IsOpen())\n+  {\n+    PanicAlertFmtT(\n+        "Failed to open the output file \\"{0}\\".\\n"\n+        "Check that you have permissions to write the target folder and that the media can "\n+        "be written.",\n+        outfile_path);\n+    return false;\n+  }\n+\n+  const u64 disc_size = infile->GetDataSize();\n+\n+  // These match the values used by standard WBFS tools (wwt, WBFS Manager)\n+  static constexpr u8 hd_sector_shift = 9;\n+  static constexpr u8 wbfs_sector_shift = 21;\n+  static constexpr u64 hd_sector_size = 1ull << hd_sector_shift;\n+  static constexpr u64 wbfs_sector_size = 1ull << wbfs_sector_shift;\n+\n+  const u64 blocks_per_disc = (disc_size + wbfs_sector_size - 1) / wbfs_sector_size;\n+  const u64 disc_info_size =\n+      Common::AlignUp(WII_DISC_HEADER_SIZE + blocks_per_disc * sizeof(u16), hd_sector_size);\n+\n+  // Read disc header (first 256 bytes contain disc_id, disc_num, title, etc.)\n+  std::vector<u8> disc_header(WII_DISC_HEADER_SIZE, 0);\n+  if (!infile->Read(0, WII_DISC_HEADER_SIZE, disc_header.data()))\n+  {\n+    PanicAlertFmtT("Failed to read from the input file \\"{0}\\".", infile_path);\n+    return false;\n+  }\n+\n+  // Use Volume for partition info and decrypted reads\n+  struct PartitionInfo\n+  {\n+    u64 data_offset;\n+    u64 data_size;\n+    Partition partition;\n+  };\n+  std::vector<PartitionInfo> partitions;\n+\n+  std::unique_ptr<VolumeDisc> volume = CreateDisc(infile_path);\n+  if (volume)\n+  {\n+    for (const Partition& partition : volume->GetPartitions())\n+    {\n+      const std::optional<u64> data_offset =\n+          volume->ReadSwappedAndShifted(partition.offset + 0x2B8, PARTITION_NONE);\n+      const std::optional<u64> data_size =\n+          volume->ReadSwappedAndShifted(partition.offset + 0x2BC, PARTITION_NONE);', 'path': 'Source/Core/DiscIO/WbfsBlob.cpp', 'position': 354, 'original_position': 354, 'commit_id': '24b41d58df2315831b74f76b95417f2739d02f9d', 'user': {'login': 'phire', 'id': 138484, 'node_id': 'MDQ6VXNlcjEzODQ4NA==', 'avatar_url': 'https://avatars.githubusercontent.com/u/138484?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/phire', 'html_url': 'https://github.com/phire', 'followers_url': 'https://api.github.com/users/phire/followers', 'following_url': 'https://api.github.com/users/phire/following{/other_user}', 'gists_url': 'https://api.github.com/users/phire/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/phire/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/phire/subscriptions', 'organizations_url': 'https://api.github.com/users/phire/orgs', 'repos_url': 'https://api.github.com/users/phire/repos', 'events_url': 'https://api.github.com/users/phire/events{/privacy}', 'received_events_url': 'https://api.github.com/users/phire/received_events', 'type': 'User', 'user_view_type': 'public', 'site_admin': False}, 'body': 'Is this really the best way?\n\nI guess so. Maybe VolumeWii needs some refactoring to better expose partition info. ', 'created_at': '2026-07-18T23:14:45Z', 'updated_at': '2026-07-18T23:14:45Z', 'html_url': 'https://github.com/dolphin-emu/dolphin/pull/14731#discussion_r3609382108', 'pull_request_url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/14731', 'author_association': 'MEMBER', '_links': {'self': {'href': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/comments/3609382108'}, 'html': {'href': 'https://github.com/dolphin-emu/dolphin/pull/14731#discussion_r3609382108'}, 'pull_request': {'href': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/14731'}}, 'original_commit_id': '24b41d58df2315831b74f76b95417f2739d02f9d', 'reactions': {'url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/comments/3609382108/reactions', 'total_count': 0, '+1': 0, '-1': 0, 'laugh': 0, 'hooray': 0, 'confused': 0, 'heart': 0, 'rocket': 0, 'eyes': 0}}], 'type': 'gh_pull_request_review'}
2026-07-18T23:06:02.346452	{'source': 'ghhookparser', 'repo': 'dolphin-emu/dolphin', 'author': 'phire', 'action': 'submitted', 'pr_id': 14731, 'pr_title': 'Convert To WBFS Support', 'state': 'commented', 'url': 'https://github.com/dolphin-emu/dolphin/pull/14731#pullrequestreview-4729447426', 'comments': [{'id': 3609363364, 'node_id': 'PRRC_kwDOALCn2M7XIoOk', 'url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/comments/3609363364', 'pull_request_review_id': 4729447426, 'diff_hunk': '@@ -186,7 +380,304 @@ std::unique_ptr<WbfsFileReader> WbfsFileReader::Create(File::DirectIOFile file,\n   if (!reader->IsGood())\n     reader.reset();\n \n+  if (reader && reader->m_has_nkit_header)\n+    reader->ReadPartitionInfo();\n+\n   return reader;\n }\n \n+// Converts any disc image to WBFS with an NKit v2 header for lossless round-trips.\n+// Strips disc-level junk and partition-level junk (encrypted sectors whose decrypted\n+// content is zero or LFG padding), records a junk bitmap for reconstruction.\n+// See: https://github.com/dolphin-emu/dolphin/pull/14731\n+bool ConvertToWBFS(BlobReader* infile, const std::string& infile_path,\n+                   const std::string& outfile_path, const CompressCB& callback)\n+{\n+  ASSERT(infile->GetDataSizeType() == DataSizeType::Accurate ||\n+         infile->GetDataSizeType() == DataSizeType::UpperBound);\n+\n+  File::DirectIOFile outfile(outfile_path, File::AccessMode::Write);\n+  if (!outfile.IsOpen())\n+  {\n+    PanicAlertFmtT(\n+        "Failed to open the output file \\"{0}\\".\\n"\n+        "Check that you have permissions to write the target folder and that the media can "\n+        "be written.",\n+        outfile_path);\n+    return false;\n+  }\n+\n+  const u64 disc_size = infile->GetDataSize();\n+\n+  // These match the values used by standard WBFS tools (wwt, WBFS Manager)\n+  static constexpr u8 hd_sector_shift = 9;\n+  static constexpr u8 wbfs_sector_shift = 21;\n+  static constexpr u64 hd_sector_size = 1ull << hd_sector_shift;\n+  static constexpr u64 wbfs_sector_size = 1ull << wbfs_sector_shift;\n+\n+  const u64 blocks_per_disc = (disc_size + wbfs_sector_size - 1) / wbfs_sector_size;\n+  const u64 disc_info_size =\n+      Common::AlignUp(WII_DISC_HEADER_SIZE + blocks_per_disc * sizeof(u16), hd_sector_size);\n+\n+  // Read disc header (first 256 bytes contain disc_id, disc_num, title, etc.)\n+  std::vector<u8> disc_header(WII_DISC_HEADER_SIZE, 0);\n+  if (!infile->Read(0, WII_DISC_HEADER_SIZE, disc_header.data()))\n+  {\n+    PanicAlertFmtT("Failed to read from the input file \\"{0}\\".", infile_path);\n+    return false;\n+  }\n+\n+  // Use Volume for partition info and decrypted reads\n+  struct PartitionInfo\n+  {\n+    u64 data_offset;\n+    u64 data_size;\n+    Partition partition;\n+  };\n+  std::vector<PartitionInfo> partitions;\n+\n+  std::unique_ptr<VolumeDisc> volume = CreateDisc(infile_path);\n+  if (volume)\n+  {\n+    for (const Partition& partition : volume->GetPartitions())\n+    {\n+      const std::optional<u64> data_offset =\n+          volume->ReadSwappedAndShifted(partition.offset + 0x2B8, PARTITION_NONE);\n+      const std::optional<u64> data_size =\n+          volume->ReadSwappedAndShifted(partition.offset + 0x2BC, PARTITION_NONE);\n+      if (!data_offset || !data_size)\n+        continue;\n+\n+      PartitionInfo info;\n+      info.data_offset = partition.offset + *data_offset;\n+      info.data_size = *data_size;\n+      info.partition = partition;\n+      partitions.push_back(info);\n+    }\n+  }\n+\n+  // NKit v2 gap type bitmap: 1 bit per block, MSB-first, always sized for dual-layer\n+  const u64 gap_type_blocks = (DL_DVD_SIZE + wbfs_sector_size - 1) / wbfs_sector_size;\n+  const u64 gap_type_bytes = (gap_type_blocks + 7) / 8;\n+  std::vector<u8> gap_type(gap_type_bytes, 0);\n+\n+  // Compute data_start up front so we can write sectors during the scan\n+  const u64 data_start = Common::AlignUp(hd_sector_size + disc_info_size, wbfs_sector_size);\n+  const u16 wlba_base = static_cast<u16>(data_start / wbfs_sector_size);\n+\n+  // Single pass: scan, classify, hash, and write used sectors in one loop\n+  std::vector<u8> sector_buf(wbfs_sector_size, 0);\n+  std::vector<u16> wlba_table(blocks_per_disc, 0);\n+  u16 used_count = 0;\n+\n+  // NKit v2 stores four hash digests for verification\n+  auto sha1_ctx = Common::SHA1::CreateContext();\n+  u32 crc = Common::StartCRC32();\n+  mbedtls_md5_context md5_ctx{};\n+  mbedtls_md5_init(&md5_ctx);\n+  mbedtls_md5_starts_ret(&md5_ctx);\n+  XXH64_state_t* xxh_state = XXH64_createState();\n+  XXH64_reset(xxh_state, 0);\n+\n+  for (u64 i = 0; i < blocks_per_disc; i++)\n+  {\n+    if (i % 100 == 0)\n+    {\n+      const bool was_cancelled =\n+          !callback(Common::GetStringT("Converting"),\n+                    static_cast<float>(i) / static_cast<float>(blocks_per_disc));\n+      if (was_cancelled)\n+      {\n+        XXH64_freeState(xxh_state);\n+        mbedtls_md5_free(&md5_ctx);\n+        outfile.Close();\n+        File::Delete(outfile_path);\n+        return false;\n+      }\n+    }\n+\n+    const u64 offset = i * wbfs_sector_size;\n+    const size_t sz = static_cast<size_t>(std::min(wbfs_sector_size, disc_size - offset));\n+\n+    if (!infile->Read(offset, sz, sector_buf.data()))\n+    {\n+      PanicAlertFmtT("Failed to read from the input file \\"{0}\\".", infile_path);\n+      XXH64_freeState(xxh_state);\n+      mbedtls_md5_free(&md5_ctx);\n+      outfile.Close();\n+      File::Delete(outfile_path);\n+      return false;\n+    }\n+\n+    // Update all four hashes with the full disc data\n+    sha1_ctx->Update(sector_buf.data(), sz);\n+    crc = Common::UpdateCRC32(crc, sector_buf.data(), sz);\n+    mbedtls_md5_update_ret(&md5_ctx, sector_buf.data(), sz);\n+    XXH64_update(xxh_state, sector_buf.data(), sz);\n+\n+    // Find which partition (if any) this block belongs to\n+    const u32 start_sector = static_cast<u32>(offset / VolumeWii::BLOCK_TOTAL_SIZE);\n+    const u32 end_sector = static_cast<u32>((offset + sz) / VolumeWii::BLOCK_TOTAL_SIZE);\n+    const auto it = std::ranges::find_if(partitions, [&](const PartitionInfo& p) {\n+      const u32 p_start = static_cast<u32>(p.data_offset / VolumeWii::BLOCK_TOTAL_SIZE);\n+      const u32 p_end =\n+          static_cast<u32>((p.data_offset + p.data_size) / VolumeWii::BLOCK_TOTAL_SIZE);', 'path': 'Source/Core/DiscIO/WbfsBlob.cpp', 'position': 431, 'original_position': 431, 'commit_id': '24b41d58df2315831b74f76b95417f2739d02f9d', 'user': {'login': 'phire', 'id': 138484, 'node_id': 'MDQ6VXNlcjEzODQ4NA==', 'avatar_url': 'https://avatars.githubusercontent.com/u/138484?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/phire', 'html_url': 'https://github.com/phire', 'followers_url': 'https://api.github.com/users/phire/followers', 'following_url': 'https://api.github.com/users/phire/following{/other_user}', 'gists_url': 'https://api.github.com/users/phire/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/phire/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/phire/subscriptions', 'organizations_url': 'https://api.github.com/users/phire/orgs', 'repos_url': 'https://api.github.com/users/phire/repos', 'events_url': 'https://api.github.com/users/phire/events{/privacy}', 'received_events_url': 'https://api.github.com/users/phire/received_events', 'type': 'User', 'user_view_type': 'public', 'site_admin': False}, 'body': "Don't all these divisions cancel out? I think you can compare the offsets directly. ", 'created_at': '2026-07-18T23:05:59Z', 'updated_at': '2026-07-18T23:06:00Z', 'html_url': 'https://github.com/dolphin-emu/dolphin/pull/14731#discussion_r3609363364', 'pull_request_url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/14731', 'author_association': 'MEMBER', '_links': {'self': {'href': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/comments/3609363364'}, 'html': {'href': 'https://github.com/dolphin-emu/dolphin/pull/14731#discussion_r3609363364'}, 'pull_request': {'href': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/14731'}}, 'original_commit_id': '24b41d58df2315831b74f76b95417f2739d02f9d', 'reactions': {'url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/comments/3609363364/reactions', 'total_count': 0, '+1': 0, '-1': 0, 'laugh': 0, 'hooray': 0, 'confused': 0, 'heart': 0, 'rocket': 0, 'eyes': 0}}], 'type': 'gh_pull_request_review'}
2026-07-18T22:54:54.428643	{'source': 'ghhookparser', 'repo': 'dolphin-emu/dolphin', 'author': 'phire', 'action': 'submitted', 'pr_id': 14475, 'pr_title': 'CMake: Replace the Visual Studio project', 'state': 'approved', 'url': 'https://github.com/dolphin-emu/dolphin/pull/14475#pullrequestreview-4729435306', 'comments': [], 'type': 'gh_pull_request_review'}
2026-07-18T22:51:01.273188	{'source': 'ghhookparser', 'repo': 'dolphin-emu/sadm', 'author': 'phire', 'action': 'submitted', 'pr_id': 204, 'pr_title': 'Update buildbot configuration to use new CMake presets', 'state': 'approved', 'url': 'https://github.com/dolphin-emu/sadm/pull/204#pullrequestreview-4729430995', 'comments': [], 'type': 'gh_pull_request_review'}
2026-07-18T22:26:25.584707	{'source': 'ghhookparser', 'repo': 'dolphin-emu/dolphin', 'author': 'phire', 'action': 'submitted', 'pr_id': 14731, 'pr_title': 'Convert To WBFS Support', 'state': 'commented', 'url': 'https://github.com/dolphin-emu/dolphin/pull/14731#pullrequestreview-4729322283', 'comments': [{'id': 3609218797, 'node_id': 'PRRC_kwDOALCn2M7XIE7t', 'url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/comments/3609218797', 'pull_request_review_id': 4729322283, 'diff_hunk': '@@ -119,22 +144,191 @@ bool WbfsFileReader::ReadHeader()\n   return m_header.disc_table[0] != 0;\n }\n \n+bool WbfsFileReader::ReadNKitHeader()\n+{\n+  const u64 gap_type_blocks = (DL_DVD_SIZE + m_wbfs_sector_size - 1) / m_wbfs_sector_size;\n+  m_nkit_info = NKit::ReadHeaderFromFile(m_files[0].file, NKit::HEADER_OFFSET, gap_type_blocks);\n+  if (!m_nkit_info.valid)\n+    return false;\n+\n+  m_has_nkit_header = true;\n+  return true;\n+}\n+\n+bool WbfsFileReader::IsBlockStored(u64 block_index) const\n+{\n+  return block_index < m_blocks_per_disc && m_wlba_table[block_index] != 0;\n+}\n+\n+bool WbfsFileReader::IsGapJunk(u64 block_index) const\n+{\n+  return NKit::IsGapJunk(m_nkit_info.gap_type, block_index);\n+}\n+\n+void WbfsFileReader::GenerateJunkData(u64 disc_offset, u64 size, u8* out) const', 'path': 'Source/Core/DiscIO/WbfsBlob.cpp', 'position': 112, 'original_position': 112, 'commit_id': '24b41d58df2315831b74f76b95417f2739d02f9d', 'user': {'login': 'phire', 'id': 138484, 'node_id': 'MDQ6VXNlcjEzODQ4NA==', 'avatar_url': 'https://avatars.githubusercontent.com/u/138484?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/phire', 'html_url': 'https://github.com/phire', 'followers_url': 'https://api.github.com/users/phire/followers', 'following_url': 'https://api.github.com/users/phire/following{/other_user}', 'gists_url': 'https://api.github.com/users/phire/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/phire/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/phire/subscriptions', 'organizations_url': 'https://api.github.com/users/phire/orgs', 'repos_url': 'https://api.github.com/users/phire/repos', 'events_url': 'https://api.github.com/users/phire/events{/privacy}', 'received_events_url': 'https://api.github.com/users/phire/received_events', 'type': 'User', 'user_view_type': 'public', 'site_admin': False}, 'body': 'Can replace size/out with a `std::span` (same with FillJunkData) ', 'created_at': '2026-07-18T21:23:14Z', 'updated_at': '2026-07-18T22:26:23Z', 'html_url': 'https://github.com/dolphin-emu/dolphin/pull/14731#discussion_r3609218797', 'pull_request_url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/14731', 'author_association': 'MEMBER', '_links': {'self': {'href': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/comments/3609218797'}, 'html': {'href': 'https://github.com/dolphin-emu/dolphin/pull/14731#discussion_r3609218797'}, 'pull_request': {'href': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/14731'}}, 'original_commit_id': '24b41d58df2315831b74f76b95417f2739d02f9d', 'reactions': {'url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/comments/3609218797/reactions', 'total_count': 0, '+1': 0, '-1': 0, 'laugh': 0, 'hooray': 0, 'confused': 0, 'heart': 0, 'rocket': 0, 'eyes': 0}}, {'id': 3609251889, 'node_id': 'PRRC_kwDOALCn2M7XINAx', 'url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/comments/3609251889', 'pull_request_review_id': 4729322283, 'diff_hunk': '@@ -186,7 +380,304 @@ std::unique_ptr<WbfsFileReader> WbfsFileReader::Create(File::DirectIOFile file,\n   if (!reader->IsGood())\n     reader.reset();\n \n+  if (reader && reader->m_has_nkit_header)\n+    reader->ReadPartitionInfo();\n+\n   return reader;\n }\n \n+// Converts any disc image to WBFS with an NKit v2 header for lossless round-trips.\n+// Strips disc-level junk and partition-level junk (encrypted sectors whose decrypted\n+// content is zero or LFG padding), records a junk bitmap for reconstruction.\n+// See: https://github.com/dolphin-emu/dolphin/pull/14731\n+bool ConvertToWBFS(BlobReader* infile, const std::string& infile_path,\n+                   const std::string& outfile_path, const CompressCB& callback)\n+{\n+  ASSERT(infile->GetDataSizeType() == DataSizeType::Accurate ||\n+         infile->GetDataSizeType() == DataSizeType::UpperBound);\n+\n+  File::DirectIOFile outfile(outfile_path, File::AccessMode::Write);\n+  if (!outfile.IsOpen())\n+  {\n+    PanicAlertFmtT(\n+        "Failed to open the output file \\"{0}\\".\\n"\n+        "Check that you have permissions to write the target folder and that the media can "\n+        "be written.",\n+        outfile_path);\n+    return false;\n+  }\n+\n+  const u64 disc_size = infile->GetDataSize();\n+\n+  // These match the values used by standard WBFS tools (wwt, WBFS Manager)\n+  static constexpr u8 hd_sector_shift = 9;\n+  static constexpr u8 wbfs_sector_shift = 21;\n+  static constexpr u64 hd_sector_size = 1ull << hd_sector_shift;\n+  static constexpr u64 wbfs_sector_size = 1ull << wbfs_sector_shift;\n+\n+  const u64 blocks_per_disc = (disc_size + wbfs_sector_size - 1) / wbfs_sector_size;\n+  const u64 disc_info_size =\n+      Common::AlignUp(WII_DISC_HEADER_SIZE + blocks_per_disc * sizeof(u16), hd_sector_size);\n+\n+  // Read disc header (first 256 bytes contain disc_id, disc_num, title, etc.)\n+  std::vector<u8> disc_header(WII_DISC_HEADER_SIZE, 0);\n+  if (!infile->Read(0, WII_DISC_HEADER_SIZE, disc_header.data()))\n+  {\n+    PanicAlertFmtT("Failed to read from the input file \\"{0}\\".", infile_path);\n+    return false;\n+  }\n+\n+  // Use Volume for partition info and decrypted reads\n+  struct PartitionInfo\n+  {\n+    u64 data_offset;\n+    u64 data_size;\n+    Partition partition;\n+  };\n+  std::vector<PartitionInfo> partitions;\n+\n+  std::unique_ptr<VolumeDisc> volume = CreateDisc(infile_path);\n+  if (volume)\n+  {\n+    for (const Partition& partition : volume->GetPartitions())\n+    {\n+      const std::optional<u64> data_offset =\n+          volume->ReadSwappedAndShifted(partition.offset + 0x2B8, PARTITION_NONE);\n+      const std::optional<u64> data_size =\n+          volume->ReadSwappedAndShifted(partition.offset + 0x2BC, PARTITION_NONE);\n+      if (!data_offset || !data_size)\n+        continue;\n+\n+      PartitionInfo info;\n+      info.data_offset = partition.offset + *data_offset;\n+      info.data_size = *data_size;\n+      info.partition = partition;\n+      partitions.push_back(info);\n+    }\n+  }\n+\n+  // NKit v2 gap type bitmap: 1 bit per block, MSB-first, always sized for dual-layer\n+  const u64 gap_type_blocks = (DL_DVD_SIZE + wbfs_sector_size - 1) / wbfs_sector_size;\n+  const u64 gap_type_bytes = (gap_type_blocks + 7) / 8;\n+  std::vector<u8> gap_type(gap_type_bytes, 0);\n+\n+  // Compute data_start up front so we can write sectors during the scan\n+  const u64 data_start = Common::AlignUp(hd_sector_size + disc_info_size, wbfs_sector_size);\n+  const u16 wlba_base = static_cast<u16>(data_start / wbfs_sector_size);\n+\n+  // Single pass: scan, classify, hash, and write used sectors in one loop\n+  std::vector<u8> sector_buf(wbfs_sector_size, 0);\n+  std::vector<u16> wlba_table(blocks_per_disc, 0);\n+  u16 used_count = 0;\n+\n+  // NKit v2 stores four hash digests for verification\n+  auto sha1_ctx = Common::SHA1::CreateContext();\n+  u32 crc = Common::StartCRC32();\n+  mbedtls_md5_context md5_ctx{};\n+  mbedtls_md5_init(&md5_ctx);\n+  mbedtls_md5_starts_ret(&md5_ctx);\n+  XXH64_state_t* xxh_state = XXH64_createState();\n+  XXH64_reset(xxh_state, 0);\n+\n+  for (u64 i = 0; i < blocks_per_disc; i++)\n+  {\n+    if (i % 100 == 0)\n+    {\n+      const bool was_cancelled =\n+          !callback(Common::GetStringT("Converting"),\n+                    static_cast<float>(i) / static_cast<float>(blocks_per_disc));\n+      if (was_cancelled)\n+      {\n+        XXH64_freeState(xxh_state);\n+        mbedtls_md5_free(&md5_ctx);\n+        outfile.Close();\n+        File::Delete(outfile_path);\n+        return false;\n+      }\n+    }\n+\n+    const u64 offset = i * wbfs_sector_size;\n+    const size_t sz = static_cast<size_t>(std::min(wbfs_sector_size, disc_size - offset));\n+\n+    if (!infile->Read(offset, sz, sector_buf.data()))', 'path': 'Source/Core/DiscIO/WbfsBlob.cpp', 'position': 409, 'original_position': 409, 'commit_id': '24b41d58df2315831b74f76b95417f2739d02f9d', 'user': {'login': 'phire', 'id': 138484, 'node_id': 'MDQ6VXNlcjEzODQ4NA==', 'avatar_url': 'https://avatars.githubusercontent.com/u/138484?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/phire', 'html_url': 'https://github.com/phire', 'followers_url': 'https://api.github.com/users/phire/followers', 'following_url': 'https://api.github.com/users/phire/following{/other_user}', 'gists_url': 'https://api.github.com/users/phire/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/phire/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/phire/subscriptions', 'organizations_url': 'https://api.github.com/users/phire/orgs', 'repos_url': 'https://api.github.com/users/phire/repos', 'events_url': 'https://api.github.com/users/phire/events{/privacy}', 'received_events_url': 'https://api.github.com/users/phire/received_events', 'type': 'User', 'user_view_type': 'public', 'site_admin': False}, 'body': "Don't read here. \nIf the sector is in a partition and is either junk or zeros, there is no need to fetch the encrypted version. That's just going to trigger an unnecessary encrypt operation for RVZ/WIA inputs.\n\nOnce we discover the sector is outside a partition, or contains data, then we can read/encrypt it. ", 'created_at': '2026-07-18T21:46:22Z', 'updated_at': '2026-07-18T22:26:23Z', 'html_url': 'https://github.com/dolphin-emu/dolphin/pull/14731#discussion_r3609251889', 'pull_request_url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/14731', 'author_association': 'MEMBER', '_links': {'self': {'href': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/comments/3609251889'}, 'html': {'href': 'https://github.com/dolphin-emu/dolphin/pull/14731#discussion_r3609251889'}, 'pull_request': {'href': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/14731'}}, 'original_commit_id': '24b41d58df2315831b74f76b95417f2739d02f9d', 'reactions': {'url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/comments/3609251889/reactions', 'total_count': 0, '+1': 0, '-1': 0, 'laugh': 0, 'hooray': 0, 'confused': 0, 'heart': 0, 'rocket': 0, 'eyes': 0}}, {'id': 3609258421, 'node_id': 'PRRC_kwDOALCn2M7XIOm1', 'url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/comments/3609258421', 'pull_request_review_id': 4729322283, 'diff_hunk': '@@ -186,7 +380,304 @@ std::unique_ptr<WbfsFileReader> WbfsFileReader::Create(File::DirectIOFile file,\n   if (!reader->IsGood())\n     reader.reset();\n \n+  if (reader && reader->m_has_nkit_header)\n+    reader->ReadPartitionInfo();\n+\n   return reader;\n }\n \n+// Converts any disc image to WBFS with an NKit v2 header for lossless round-trips.\n+// Strips disc-level junk and partition-level junk (encrypted sectors whose decrypted\n+// content is zero or LFG padding), records a junk bitmap for reconstruction.\n+// See: https://github.com/dolphin-emu/dolphin/pull/14731\n+bool ConvertToWBFS(BlobReader* infile, const std::string& infile_path,\n+                   const std::string& outfile_path, const CompressCB& callback)\n+{\n+  ASSERT(infile->GetDataSizeType() == DataSizeType::Accurate ||\n+         infile->GetDataSizeType() == DataSizeType::UpperBound);\n+\n+  File::DirectIOFile outfile(outfile_path, File::AccessMode::Write);\n+  if (!outfile.IsOpen())\n+  {\n+    PanicAlertFmtT(\n+        "Failed to open the output file \\"{0}\\".\\n"\n+        "Check that you have permissions to write the target folder and that the media can "\n+        "be written.",\n+        outfile_path);\n+    return false;\n+  }\n+\n+  const u64 disc_size = infile->GetDataSize();\n+\n+  // These match the values used by standard WBFS tools (wwt, WBFS Manager)\n+  static constexpr u8 hd_sector_shift = 9;\n+  static constexpr u8 wbfs_sector_shift = 21;\n+  static constexpr u64 hd_sector_size = 1ull << hd_sector_shift;\n+  static constexpr u64 wbfs_sector_size = 1ull << wbfs_sector_shift;\n+\n+  const u64 blocks_per_disc = (disc_size + wbfs_sector_size - 1) / wbfs_sector_size;\n+  const u64 disc_info_size =\n+      Common::AlignUp(WII_DISC_HEADER_SIZE + blocks_per_disc * sizeof(u16), hd_sector_size);\n+\n+  // Read disc header (first 256 bytes contain disc_id, disc_num, title, etc.)\n+  std::vector<u8> disc_header(WII_DISC_HEADER_SIZE, 0);\n+  if (!infile->Read(0, WII_DISC_HEADER_SIZE, disc_header.data()))\n+  {\n+    PanicAlertFmtT("Failed to read from the input file \\"{0}\\".", infile_path);\n+    return false;\n+  }\n+\n+  // Use Volume for partition info and decrypted reads\n+  struct PartitionInfo\n+  {\n+    u64 data_offset;\n+    u64 data_size;\n+    Partition partition;\n+  };\n+  std::vector<PartitionInfo> partitions;\n+\n+  std::unique_ptr<VolumeDisc> volume = CreateDisc(infile_path);\n+  if (volume)\n+  {\n+    for (const Partition& partition : volume->GetPartitions())\n+    {\n+      const std::optional<u64> data_offset =\n+          volume->ReadSwappedAndShifted(partition.offset + 0x2B8, PARTITION_NONE);\n+      const std::optional<u64> data_size =\n+          volume->ReadSwappedAndShifted(partition.offset + 0x2BC, PARTITION_NONE);\n+      if (!data_offset || !data_size)\n+        continue;\n+\n+      PartitionInfo info;\n+      info.data_offset = partition.offset + *data_offset;\n+      info.data_size = *data_size;\n+      info.partition = partition;\n+      partitions.push_back(info);\n+    }\n+  }\n+\n+  // NKit v2 gap type bitmap: 1 bit per block, MSB-first, always sized for dual-layer\n+  const u64 gap_type_blocks = (DL_DVD_SIZE + wbfs_sector_size - 1) / wbfs_sector_size;\n+  const u64 gap_type_bytes = (gap_type_blocks + 7) / 8;\n+  std::vector<u8> gap_type(gap_type_bytes, 0);\n+\n+  // Compute data_start up front so we can write sectors during the scan\n+  const u64 data_start = Common::AlignUp(hd_sector_size + disc_info_size, wbfs_sector_size);\n+  const u16 wlba_base = static_cast<u16>(data_start / wbfs_sector_size);\n+\n+  // Single pass: scan, classify, hash, and write used sectors in one loop\n+  std::vector<u8> sector_buf(wbfs_sector_size, 0);\n+  std::vector<u16> wlba_table(blocks_per_disc, 0);\n+  u16 used_count = 0;\n+\n+  // NKit v2 stores four hash digests for verification\n+  auto sha1_ctx = Common::SHA1::CreateContext();\n+  u32 crc = Common::StartCRC32();\n+  mbedtls_md5_context md5_ctx{};\n+  mbedtls_md5_init(&md5_ctx);\n+  mbedtls_md5_starts_ret(&md5_ctx);\n+  XXH64_state_t* xxh_state = XXH64_createState();\n+  XXH64_reset(xxh_state, 0);\n+\n+  for (u64 i = 0; i < blocks_per_disc; i++)\n+  {\n+    if (i % 100 == 0)\n+    {\n+      const bool was_cancelled =\n+          !callback(Common::GetStringT("Converting"),\n+                    static_cast<float>(i) / static_cast<float>(blocks_per_disc));\n+      if (was_cancelled)\n+      {\n+        XXH64_freeState(xxh_state);\n+        mbedtls_md5_free(&md5_ctx);\n+        outfile.Close();\n+        File::Delete(outfile_path);\n+        return false;\n+      }\n+    }\n+\n+    const u64 offset = i * wbfs_sector_size;\n+    const size_t sz = static_cast<size_t>(std::min(wbfs_sector_size, disc_size - offset));\n+\n+    if (!infile->Read(offset, sz, sector_buf.data()))\n+    {\n+      PanicAlertFmtT("Failed to read from the input file \\"{0}\\".", infile_path);\n+      XXH64_freeState(xxh_state);\n+      mbedtls_md5_free(&md5_ctx);\n+      outfile.Close();\n+      File::Delete(outfile_path);\n+      return false;\n+    }\n+\n+    // Update all four hashes with the full disc data\n+    sha1_ctx->Update(sector_buf.data(), sz);\n+    crc = Common::UpdateCRC32(crc, sector_buf.data(), sz);\n+    mbedtls_md5_update_ret(&md5_ctx, sector_buf.data(), sz);\n+    XXH64_update(xxh_state, sector_buf.data(), sz);\n+\n+    // Find which partition (if any) this block belongs to\n+    const u32 start_sector = static_cast<u32>(offset / VolumeWii::BLOCK_TOTAL_SIZE);\n+    const u32 end_sector = static_cast<u32>((offset + sz) / VolumeWii::BLOCK_TOTAL_SIZE);\n+    const auto it = std::ranges::find_if(partitions, [&](const PartitionInfo& p) {\n+      const u32 p_start = static_cast<u32>(p.data_offset / VolumeWii::BLOCK_TOTAL_SIZE);\n+      const u32 p_end =\n+          static_cast<u32>((p.data_offset + p.data_size) / VolumeWii::BLOCK_TOTAL_SIZE);\n+      return start_sector >= p_start && end_sector <= p_end;\n+    });\n+    const PartitionInfo* pi = (it != partitions.end()) ? &*it : nullptr;\n+\n+    bool is_used = true;\n+\n+    if (pi)', 'path': 'Source/Core/DiscIO/WbfsBlob.cpp', 'position': 438, 'original_position': 438, 'commit_id': '24b41d58df2315831b74f76b95417f2739d02f9d', 'user': {'login': 'phire', 'id': 138484, 'node_id': 'MDQ6VXNlcjEzODQ4NA==', 'avatar_url': 'https://avatars.githubusercontent.com/u/138484?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/phire', 'html_url': 'https://github.com/phire', 'followers_url': 'https://api.github.com/users/phire/followers', 'following_url': 'https://api.github.com/users/phire/following{/other_user}', 'gists_url': 'https://api.github.com/users/phire/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/phire/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/phire/subscriptions', 'organizations_url': 'https://api.github.com/users/phire/orgs', 'repos_url': 'https://api.github.com/users/phire/repos', 'events_url': 'https://api.github.com/users/phire/events{/privacy}', 'received_events_url': 'https://api.github.com/users/phire/received_events', 'type': 'User', 'user_view_type': 'public', 'site_admin': False}, 'body': 'Put the result of `find_if` directly into pi\n\nThen you can skip the weird conversion to nullptr and do the check here\n\n```suggestion\n    if (pi != partitions.end())\n```', 'created_at': '2026-07-18T21:51:02Z', 'updated_at': '2026-07-18T22:26:23Z', 'html_url': 'https://github.com/dolphin-emu/dolphin/pull/14731#discussion_r3609258421', 'pull_request_url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/14731', 'author_association': 'MEMBER', '_links': {'self': {'href': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/comments/3609258421'}, 'html': {'href': 'https://github.com/dolphin-emu/dolphin/pull/14731#discussion_r3609258421'}, 'pull_request': {'href': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/14731'}}, 'original_commit_id': '24b41d58df2315831b74f76b95417f2739d02f9d', 'reactions': {'url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/comments/3609258421/reactions', 'total_count': 0, '+1': 0, '-1': 0, 'laugh': 0, 'hooray': 0, 'confused': 0, 'heart': 0, 'rocket': 0, 'eyes': 0}}, {'id': 3609262932, 'node_id': 'PRRC_kwDOALCn2M7XIPtU', 'url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/comments/3609262932', 'pull_request_review_id': 4729322283, 'diff_hunk': '@@ -186,7 +380,304 @@ std::unique_ptr<WbfsFileReader> WbfsFileReader::Create(File::DirectIOFile file,\n   if (!reader->IsGood())\n     reader.reset();\n \n+  if (reader && reader->m_has_nkit_header)\n+    reader->ReadPartitionInfo();\n+\n   return reader;\n }\n \n+// Converts any disc image to WBFS with an NKit v2 header for lossless round-trips.\n+// Strips disc-level junk and partition-level junk (encrypted sectors whose decrypted\n+// content is zero or LFG padding), records a junk bitmap for reconstruction.\n+// See: https://github.com/dolphin-emu/dolphin/pull/14731\n+bool ConvertToWBFS(BlobReader* infile, const std::string& infile_path,\n+                   const std::string& outfile_path, const CompressCB& callback)\n+{\n+  ASSERT(infile->GetDataSizeType() == DataSizeType::Accurate ||\n+         infile->GetDataSizeType() == DataSizeType::UpperBound);\n+\n+  File::DirectIOFile outfile(outfile_path, File::AccessMode::Write);\n+  if (!outfile.IsOpen())\n+  {\n+    PanicAlertFmtT(\n+        "Failed to open the output file \\"{0}\\".\\n"\n+        "Check that you have permissions to write the target folder and that the media can "\n+        "be written.",\n+        outfile_path);\n+    return false;\n+  }\n+\n+  const u64 disc_size = infile->GetDataSize();\n+\n+  // These match the values used by standard WBFS tools (wwt, WBFS Manager)\n+  static constexpr u8 hd_sector_shift = 9;\n+  static constexpr u8 wbfs_sector_shift = 21;\n+  static constexpr u64 hd_sector_size = 1ull << hd_sector_shift;\n+  static constexpr u64 wbfs_sector_size = 1ull << wbfs_sector_shift;\n+\n+  const u64 blocks_per_disc = (disc_size + wbfs_sector_size - 1) / wbfs_sector_size;\n+  const u64 disc_info_size =\n+      Common::AlignUp(WII_DISC_HEADER_SIZE + blocks_per_disc * sizeof(u16), hd_sector_size);\n+\n+  // Read disc header (first 256 bytes contain disc_id, disc_num, title, etc.)\n+  std::vector<u8> disc_header(WII_DISC_HEADER_SIZE, 0);\n+  if (!infile->Read(0, WII_DISC_HEADER_SIZE, disc_header.data()))\n+  {\n+    PanicAlertFmtT("Failed to read from the input file \\"{0}\\".", infile_path);\n+    return false;\n+  }\n+\n+  // Use Volume for partition info and decrypted reads\n+  struct PartitionInfo\n+  {\n+    u64 data_offset;\n+    u64 data_size;\n+    Partition partition;\n+  };\n+  std::vector<PartitionInfo> partitions;\n+\n+  std::unique_ptr<VolumeDisc> volume = CreateDisc(infile_path);\n+  if (volume)\n+  {\n+    for (const Partition& partition : volume->GetPartitions())\n+    {\n+      const std::optional<u64> data_offset =\n+          volume->ReadSwappedAndShifted(partition.offset + 0x2B8, PARTITION_NONE);\n+      const std::optional<u64> data_size =\n+          volume->ReadSwappedAndShifted(partition.offset + 0x2BC, PARTITION_NONE);\n+      if (!data_offset || !data_size)\n+        continue;\n+\n+      PartitionInfo info;\n+      info.data_offset = partition.offset + *data_offset;\n+      info.data_size = *data_size;\n+      info.partition = partition;\n+      partitions.push_back(info);\n+    }\n+  }\n+\n+  // NKit v2 gap type bitmap: 1 bit per block, MSB-first, always sized for dual-layer\n+  const u64 gap_type_blocks = (DL_DVD_SIZE + wbfs_sector_size - 1) / wbfs_sector_size;\n+  const u64 gap_type_bytes = (gap_type_blocks + 7) / 8;\n+  std::vector<u8> gap_type(gap_type_bytes, 0);\n+\n+  // Compute data_start up front so we can write sectors during the scan\n+  const u64 data_start = Common::AlignUp(hd_sector_size + disc_info_size, wbfs_sector_size);\n+  const u16 wlba_base = static_cast<u16>(data_start / wbfs_sector_size);\n+\n+  // Single pass: scan, classify, hash, and write used sectors in one loop\n+  std::vector<u8> sector_buf(wbfs_sector_size, 0);\n+  std::vector<u16> wlba_table(blocks_per_disc, 0);\n+  u16 used_count = 0;\n+\n+  // NKit v2 stores four hash digests for verification\n+  auto sha1_ctx = Common::SHA1::CreateContext();\n+  u32 crc = Common::StartCRC32();\n+  mbedtls_md5_context md5_ctx{};\n+  mbedtls_md5_init(&md5_ctx);\n+  mbedtls_md5_starts_ret(&md5_ctx);\n+  XXH64_state_t* xxh_state = XXH64_createState();\n+  XXH64_reset(xxh_state, 0);\n+\n+  for (u64 i = 0; i < blocks_per_disc; i++)\n+  {\n+    if (i % 100 == 0)\n+    {\n+      const bool was_cancelled =\n+          !callback(Common::GetStringT("Converting"),\n+                    static_cast<float>(i) / static_cast<float>(blocks_per_disc));\n+      if (was_cancelled)\n+      {\n+        XXH64_freeState(xxh_state);\n+        mbedtls_md5_free(&md5_ctx);\n+        outfile.Close();\n+        File::Delete(outfile_path);\n+        return false;\n+      }\n+    }\n+\n+    const u64 offset = i * wbfs_sector_size;\n+    const size_t sz = static_cast<size_t>(std::min(wbfs_sector_size, disc_size - offset));\n+\n+    if (!infile->Read(offset, sz, sector_buf.data()))\n+    {\n+      PanicAlertFmtT("Failed to read from the input file \\"{0}\\".", infile_path);\n+      XXH64_freeState(xxh_state);\n+      mbedtls_md5_free(&md5_ctx);\n+      outfile.Close();\n+      File::Delete(outfile_path);\n+      return false;\n+    }\n+\n+    // Update all four hashes with the full disc data\n+    sha1_ctx->Update(sector_buf.data(), sz);\n+    crc = Common::UpdateCRC32(crc, sector_buf.data(), sz);\n+    mbedtls_md5_update_ret(&md5_ctx, sector_buf.data(), sz);\n+    XXH64_update(xxh_state, sector_buf.data(), sz);\n+\n+    // Find which partition (if any) this block belongs to\n+    const u32 start_sector = static_cast<u32>(offset / VolumeWii::BLOCK_TOTAL_SIZE);\n+    const u32 end_sector = static_cast<u32>((offset + sz) / VolumeWii::BLOCK_TOTAL_SIZE);\n+    const auto it = std::ranges::find_if(partitions, [&](const PartitionInfo& p) {\n+      const u32 p_start = static_cast<u32>(p.data_offset / VolumeWii::BLOCK_TOTAL_SIZE);\n+      const u32 p_end =\n+          static_cast<u32>((p.data_offset + p.data_size) / VolumeWii::BLOCK_TOTAL_SIZE);\n+      return start_sector >= p_start && end_sector <= p_end;\n+    });\n+    const PartitionInfo* pi = (it != partitions.end()) ? &*it : nullptr;\n+\n+    bool is_used = true;\n+\n+    if (pi)\n+    {\n+      // Partition data: use Volume::Read to get decrypted data for junk/zero checks.\n+      // All-zero and all-junk are checked separately - mixed blocks are stored.\n+      bool all_zero = true;\n+      bool all_junk = true;\n+      for (u64 sub = 0; sub < sz; sub += VolumeWii::BLOCK_TOTAL_SIZE)\n+      {\n+        const u64 abs = offset + sub;\n+        const u64 sector_in_partition = (abs - pi->data_offset) / VolumeWii::BLOCK_TOTAL_SIZE;\n+        const u64 partition_offset = sector_in_partition * VolumeWii::BLOCK_DATA_SIZE;\n+\n+        u8 decrypted[VolumeWii::BLOCK_DATA_SIZE];\n+        if (!volume->Read(partition_offset, VolumeWii::BLOCK_DATA_SIZE, decrypted, pi->partition))\n+          break;\n+\n+        const bool sector_zero = std::ranges::all_of(decrypted, [](u8 b) { return b == 0; });\n+        if (!sector_zero)\n+        {\n+          all_zero = false;\n+          const bool sector_junk = LaggedFibonacciGenerator::IsJunkBlock(\n+              decrypted, VolumeWii::BLOCK_DATA_SIZE, partition_offset, disc_header.data(),\n+              disc_header[6]);\n+          if (!sector_junk)\n+            all_junk = false;\n+        }\n+\n+        if (!all_zero && !all_junk)\n+          break;\n+      }\n+\n+      if (all_zero || all_junk)\n+      {\n+        if (all_junk && !all_zero)\n+          gap_type[i / 8] |= static_cast<u8>(1 << (7 - (i & 7)));\n+        is_used = false;\n+      }\n+    }\n+    else\n+    {\n+      // Non-partition data: check disc-level zero and junk patterns\n+      const bool is_zero = std::ranges::all_of(sector_buf, [](u8 b) { return b == 0; });\n+      if (is_zero)\n+      {\n+        is_used = false;\n+      }\n+      else if (LaggedFibonacciGenerator::IsJunkBlock(sector_buf.data(), sz, offset,\n+                                                     disc_header.data(), disc_header[6]))\n+      {\n+        gap_type[i / 8] |= static_cast<u8>(1 << (7 - (i & 7)));\n+        is_used = false;\n+      }\n+    }\n+\n+    if (is_used)\n+    {\n+      // Write sector directly to output\n+      const u64 out_offset = data_start + static_cast<u64>(used_count) * wbfs_sector_size;\n+      outfile.Seek(out_offset, File::SeekOrigin::Begin);', 'path': 'Source/Core/DiscIO/WbfsBlob.cpp', 'position': 496, 'original_position': 496, 'commit_id': '24b41d58df2315831b74f76b95417f2739d02f9d', 'user': {'login': 'phire', 'id': 138484, 'node_id': 'MDQ6VXNlcjEzODQ4NA==', 'avatar_url': 'https://avatars.githubusercontent.com/u/138484?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/phire', 'html_url': 'https://github.com/phire', 'followers_url': 'https://api.github.com/users/phire/followers', 'following_url': 'https://api.github.com/users/phire/following{/other_user}', 'gists_url': 'https://api.github.com/users/phire/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/phire/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/phire/subscriptions', 'organizations_url': 'https://api.github.com/users/phire/orgs', 'repos_url': 'https://api.github.com/users/phire/repos', 'events_url': 'https://api.github.com/users/phire/events{/privacy}', 'received_events_url': 'https://api.github.com/users/phire/received_events', 'type': 'User', 'user_view_type': 'public', 'site_admin': False}, 'body': 'Should be able to avoid the seek in the loop.\nJust seek once to `data_start` before the loop, the writes will advance to the next position.  ', 'created_at': '2026-07-18T21:54:25Z', 'updated_at': '2026-07-18T22:26:23Z', 'html_url': 'https://github.com/dolphin-emu/dolphin/pull/14731#discussion_r3609262932', 'pull_request_url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/14731', 'author_association': 'MEMBER', '_links': {'self': {'href': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/comments/3609262932'}, 'html': {'href': 'https://github.com/dolphin-emu/dolphin/pull/14731#discussion_r3609262932'}, 'pull_request': {'href': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/14731'}}, 'original_commit_id': '24b41d58df2315831b74f76b95417f2739d02f9d', 'reactions': {'url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/comments/3609262932/reactions', 'total_count': 0, '+1': 0, '-1': 0, 'laugh': 0, 'hooray': 0, 'confused': 0, 'heart': 0, 'rocket': 0, 'eyes': 0}}, {'id': 3609268698, 'node_id': 'PRRC_kwDOALCn2M7XIRHa', 'url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/comments/3609268698', 'pull_request_review_id': 4729322283, 'diff_hunk': '@@ -186,7 +380,304 @@ std::unique_ptr<WbfsFileReader> WbfsFileReader::Create(File::DirectIOFile file,\n   if (!reader->IsGood())\n     reader.reset();\n \n+  if (reader && reader->m_has_nkit_header)\n+    reader->ReadPartitionInfo();\n+\n   return reader;\n }\n \n+// Converts any disc image to WBFS with an NKit v2 header for lossless round-trips.\n+// Strips disc-level junk and partition-level junk (encrypted sectors whose decrypted\n+// content is zero or LFG padding), records a junk bitmap for reconstruction.\n+// See: https://github.com/dolphin-emu/dolphin/pull/14731\n+bool ConvertToWBFS(BlobReader* infile, const std::string& infile_path,\n+                   const std::string& outfile_path, const CompressCB& callback)\n+{\n+  ASSERT(infile->GetDataSizeType() == DataSizeType::Accurate ||\n+         infile->GetDataSizeType() == DataSizeType::UpperBound);\n+\n+  File::DirectIOFile outfile(outfile_path, File::AccessMode::Write);\n+  if (!outfile.IsOpen())\n+  {\n+    PanicAlertFmtT(\n+        "Failed to open the output file \\"{0}\\".\\n"\n+        "Check that you have permissions to write the target folder and that the media can "\n+        "be written.",\n+        outfile_path);\n+    return false;\n+  }\n+\n+  const u64 disc_size = infile->GetDataSize();\n+\n+  // These match the values used by standard WBFS tools (wwt, WBFS Manager)\n+  static constexpr u8 hd_sector_shift = 9;\n+  static constexpr u8 wbfs_sector_shift = 21;\n+  static constexpr u64 hd_sector_size = 1ull << hd_sector_shift;\n+  static constexpr u64 wbfs_sector_size = 1ull << wbfs_sector_shift;\n+\n+  const u64 blocks_per_disc = (disc_size + wbfs_sector_size - 1) / wbfs_sector_size;\n+  const u64 disc_info_size =\n+      Common::AlignUp(WII_DISC_HEADER_SIZE + blocks_per_disc * sizeof(u16), hd_sector_size);\n+\n+  // Read disc header (first 256 bytes contain disc_id, disc_num, title, etc.)\n+  std::vector<u8> disc_header(WII_DISC_HEADER_SIZE, 0);\n+  if (!infile->Read(0, WII_DISC_HEADER_SIZE, disc_header.data()))\n+  {\n+    PanicAlertFmtT("Failed to read from the input file \\"{0}\\".", infile_path);\n+    return false;\n+  }\n+\n+  // Use Volume for partition info and decrypted reads\n+  struct PartitionInfo\n+  {\n+    u64 data_offset;\n+    u64 data_size;\n+    Partition partition;\n+  };\n+  std::vector<PartitionInfo> partitions;\n+\n+  std::unique_ptr<VolumeDisc> volume = CreateDisc(infile_path);\n+  if (volume)\n+  {\n+    for (const Partition& partition : volume->GetPartitions())\n+    {\n+      const std::optional<u64> data_offset =\n+          volume->ReadSwappedAndShifted(partition.offset + 0x2B8, PARTITION_NONE);\n+      const std::optional<u64> data_size =\n+          volume->ReadSwappedAndShifted(partition.offset + 0x2BC, PARTITION_NONE);\n+      if (!data_offset || !data_size)\n+        continue;\n+\n+      PartitionInfo info;\n+      info.data_offset = partition.offset + *data_offset;\n+      info.data_size = *data_size;\n+      info.partition = partition;\n+      partitions.push_back(info);\n+    }\n+  }\n+\n+  // NKit v2 gap type bitmap: 1 bit per block, MSB-first, always sized for dual-layer\n+  const u64 gap_type_blocks = (DL_DVD_SIZE + wbfs_sector_size - 1) / wbfs_sector_size;\n+  const u64 gap_type_bytes = (gap_type_blocks + 7) / 8;\n+  std::vector<u8> gap_type(gap_type_bytes, 0);\n+\n+  // Compute data_start up front so we can write sectors during the scan\n+  const u64 data_start = Common::AlignUp(hd_sector_size + disc_info_size, wbfs_sector_size);\n+  const u16 wlba_base = static_cast<u16>(data_start / wbfs_sector_size);\n+\n+  // Single pass: scan, classify, hash, and write used sectors in one loop\n+  std::vector<u8> sector_buf(wbfs_sector_size, 0);\n+  std::vector<u16> wlba_table(blocks_per_disc, 0);\n+  u16 used_count = 0;\n+\n+  // NKit v2 stores four hash digests for verification\n+  auto sha1_ctx = Common::SHA1::CreateContext();\n+  u32 crc = Common::StartCRC32();\n+  mbedtls_md5_context md5_ctx{};\n+  mbedtls_md5_init(&md5_ctx);\n+  mbedtls_md5_starts_ret(&md5_ctx);\n+  XXH64_state_t* xxh_state = XXH64_createState();\n+  XXH64_reset(xxh_state, 0);\n+\n+  for (u64 i = 0; i < blocks_per_disc; i++)\n+  {\n+    if (i % 100 == 0)\n+    {\n+      const bool was_cancelled =\n+          !callback(Common::GetStringT("Converting"),\n+                    static_cast<float>(i) / static_cast<float>(blocks_per_disc));\n+      if (was_cancelled)\n+      {\n+        XXH64_freeState(xxh_state);\n+        mbedtls_md5_free(&md5_ctx);\n+        outfile.Close();\n+        File::Delete(outfile_path);', 'path': 'Source/Core/DiscIO/WbfsBlob.cpp', 'position': 401, 'original_position': 401, 'commit_id': '24b41d58df2315831b74f76b95417f2739d02f9d', 'user': {'login': 'phire', 'id': 138484, 'node_id': 'MDQ6VXNlcjEzODQ4NA==', 'avatar_url': 'https://avatars.githubusercontent.com/u/138484?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/phire', 'html_url': 'https://github.com/phire', 'followers_url': 'https://api.github.com/users/phire/followers', 'following_url': 'https://api.github.com/users/phire/following{/other_user}', 'gists_url': 'https://api.github.com/users/phire/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/phire/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/phire/subscriptions', 'organizations_url': 'https://api.github.com/users/phire/orgs', 'repos_url': 'https://api.github.com/users/phire/repos', 'events_url': 'https://api.github.com/users/phire/events{/privacy}', 'received_events_url': 'https://api.github.com/users/phire/received_events', 'type': 'User', 'user_view_type': 'public', 'site_admin': False}, 'body': 'Use `Common::ScopeGuard` to avoid this manual cleanup. ', 'created_at': '2026-07-18T21:58:40Z', 'updated_at': '2026-07-18T22:26:23Z', 'html_url': 'https://github.com/dolphin-emu/dolphin/pull/14731#discussion_r3609268698', 'pull_request_url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/14731', 'author_association': 'MEMBER', '_links': {'self': {'href': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/comments/3609268698'}, 'html': {'href': 'https://github.com/dolphin-emu/dolphin/pull/14731#discussion_r3609268698'}, 'pull_request': {'href': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/14731'}}, 'original_commit_id': '24b41d58df2315831b74f76b95417f2739d02f9d', 'reactions': {'url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/comments/3609268698/reactions', 'total_count': 0, '+1': 0, '-1': 0, 'laugh': 0, 'hooray': 0, 'confused': 0, 'heart': 0, 'rocket': 0, 'eyes': 0}}, {'id': 3609277919, 'node_id': 'PRRC_kwDOALCn2M7XITXf', 'url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/comments/3609277919', 'pull_request_review_id': 4729322283, 'diff_hunk': '@@ -119,22 +144,191 @@ bool WbfsFileReader::ReadHeader()\n   return m_header.disc_table[0] != 0;\n }\n \n+bool WbfsFileReader::ReadNKitHeader()\n+{\n+  const u64 gap_type_blocks = (DL_DVD_SIZE + m_wbfs_sector_size - 1) / m_wbfs_sector_size;\n+  m_nkit_info = NKit::ReadHeaderFromFile(m_files[0].file, NKit::HEADER_OFFSET, gap_type_blocks);\n+  if (!m_nkit_info.valid)\n+    return false;\n+\n+  m_has_nkit_header = true;\n+  return true;\n+}\n+\n+bool WbfsFileReader::IsBlockStored(u64 block_index) const\n+{\n+  return block_index < m_blocks_per_disc && m_wlba_table[block_index] != 0;\n+}\n+\n+bool WbfsFileReader::IsGapJunk(u64 block_index) const\n+{\n+  return NKit::IsGapJunk(m_nkit_info.gap_type, block_index);\n+}\n+\n+void WbfsFileReader::GenerateJunkData(u64 disc_offset, u64 size, u8* out) const\n+{\n+  LaggedFibonacciGenerator::FillJunkData(out, static_cast<size_t>(size), disc_offset, m_disc_id,\n+                                         m_disc_num);\n+}\n+\n+void WbfsFileReader::ReadPartitionInfo()\n+{\n+  std::unique_ptr<VolumeDisc> volume = CreateDisc(CopyReader());\n+  if (!volume)\n+    return;\n+\n+  for (const Partition& partition : volume->GetPartitions())\n+  {\n+    const auto& ticket = volume->GetTicket(partition);\n+    const std::array<u8, 16> title_key = ticket.GetTitleKey();\n+\n+    u8 data_info[8];\n+    if (!Read(partition.offset + 0x2B8, 8, data_info))\n+      continue;\n+\n+    PartitionEntry entry;\n+    entry.data_offset = partition.offset + (static_cast<u64>(Common::swap32(data_info)) << 2);\n+    entry.data_size = static_cast<u64>(Common::swap32(data_info + 4)) << 2;\n+    entry.key = title_key;\n+    m_partitions.push_back(entry);\n+  }\n+}\n+\n+const WbfsFileReader::PartitionEntry* WbfsFileReader::FindPartition(u64 disc_offset) const\n+{\n+  for (const auto& p : m_partitions)\n+  {\n+    if (disc_offset >= p.data_offset && disc_offset < p.data_offset + p.data_size)\n+      return &p;\n+  }\n+  return nullptr;\n+}\n+\n+const WbfsFileReader::PartitionEntry*\n+WbfsFileReader::FindPartitionByDataOffset(u64 partition_data_offset) const\n+{\n+  for (const auto& p : m_partitions)\n+  {\n+    if (p.data_offset == partition_data_offset)\n+      return &p;\n+  }\n+  return nullptr;\n+}\n+\n+bool WbfsFileReader::SupportsReadWiiDecrypted(u64 offset, u64 size, u64 partition_data_offset) const\n+{\n+  if (!m_has_nkit_header)\n+    return false;\n+\n+  const u64 block_in_partition = offset / VolumeWii::BLOCK_DATA_SIZE;\n+  const u64 disc_offset = partition_data_offset + block_in_partition * VolumeWii::BLOCK_TOTAL_SIZE;\n+  const u64 wbfs_block = disc_offset >> m_header.wbfs_sector_shift;\n+\n+  return wbfs_block < m_blocks_per_disc && !IsBlockStored(wbfs_block);\n+}\n+\n+bool WbfsFileReader::ReadWiiDecrypted(u64 offset, u64 size, u8* out_ptr, u64 partition_data_offset)\n+{\n+  const PartitionEntry* pe = FindPartitionByDataOffset(partition_data_offset);\n+  if (!pe)\n+    return false;\n+\n+  auto aes_ctx = Common::AES::CreateContextDecrypt(pe->key.data());\n+  std::vector<u8> encrypted(VolumeWii::BLOCK_TOTAL_SIZE);\n+  std::vector<u8> decrypted(VolumeWii::BLOCK_DATA_SIZE);\n+\n+  while (size > 0)\n+  {\n+    const u64 block_in_partition = offset / VolumeWii::BLOCK_DATA_SIZE;\n+    const u64 offset_in_block = offset % VolumeWii::BLOCK_DATA_SIZE;\n+    const u64 bytes_in_block = VolumeWii::BLOCK_DATA_SIZE - offset_in_block;\n+    const size_t read_size = static_cast<size_t>(std::min(bytes_in_block, size));\n+\n+    const u64 disc_offset =\n+        partition_data_offset + block_in_partition * VolumeWii::BLOCK_TOTAL_SIZE;\n+    const u64 wbfs_block = disc_offset >> m_header.wbfs_sector_shift;\n+\n+    if (IsBlockStored(wbfs_block))\n+    {\n+      u64 available;\n+      auto& file = SeekToCluster(disc_offset, &available);\n+      if (available < VolumeWii::BLOCK_TOTAL_SIZE ||\n+          !file.Read(encrypted.data(), VolumeWii::BLOCK_TOTAL_SIZE))\n+        return false;\n+      VolumeWii::DecryptBlockData(encrypted.data(), decrypted.data(), aes_ctx.get());\n+      std::memcpy(out_ptr, decrypted.data() + offset_in_block, read_size);\n+    }', 'path': 'Source/Core/DiscIO/WbfsBlob.cpp', 'position': 204, 'original_position': 204, 'commit_id': '24b41d58df2315831b74f76b95417f2739d02f9d', 'user': {'login': 'phire', 'id': 138484, 'node_id': 'MDQ6VXNlcjEzODQ4NA==', 'avatar_url': 'https://avatars.githubusercontent.com/u/138484?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/phire', 'html_url': 'https://github.com/phire', 'followers_url': 'https://api.github.com/users/phire/followers', 'following_url': 'https://api.github.com/users/phire/following{/other_user}', 'gists_url': 'https://api.github.com/users/phire/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/phire/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/phire/subscriptions', 'organizations_url': 'https://api.github.com/users/phire/orgs', 'repos_url': 'https://api.github.com/users/phire/repos', 'events_url': 'https://api.github.com/users/phire/events{/privacy}', 'received_events_url': 'https://api.github.com/users/phire/received_events', 'type': 'User', 'user_view_type': 'public', 'site_admin': False}, 'body': "> ReadWiiDecrypted still contains manual AES decryption for stored blocks because VolumeWii::EncryptGroup calls it directly without checking SupportsReadWiiDecrypted\n\nBut you are calling `EncryptGroup` for blocks that don't have data, right? I don't see why this would be reachable.", 'created_at': '2026-07-18T22:05:05Z', 'updated_at': '2026-07-18T22:26:23Z', 'html_url': 'https://github.com/dolphin-emu/dolphin/pull/14731#discussion_r3609277919', 'pull_request_url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/14731', 'author_association': 'MEMBER', '_links': {'self': {'href': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/comments/3609277919'}, 'html': {'href': 'https://github.com/dolphin-emu/dolphin/pull/14731#discussion_r3609277919'}, 'pull_request': {'href': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/14731'}}, 'original_commit_id': '24b41d58df2315831b74f76b95417f2739d02f9d', 'reactions': {'url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/comments/3609277919/reactions', 'total_count': 0, '+1': 0, '-1': 0, 'laugh': 0, 'hooray': 0, 'confused': 0, 'heart': 0, 'rocket': 0, 'eyes': 0}}, {'id': 3609296950, 'node_id': 'PRRC_kwDOALCn2M7XIYA2', 'url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/comments/3609296950', 'pull_request_review_id': 4729322283, 'diff_hunk': '@@ -186,7 +380,304 @@ std::unique_ptr<WbfsFileReader> WbfsFileReader::Create(File::DirectIOFile file,\n   if (!reader->IsGood())\n     reader.reset();\n \n+  if (reader && reader->m_has_nkit_header)\n+    reader->ReadPartitionInfo();\n+\n   return reader;\n }\n \n+// Converts any disc image to WBFS with an NKit v2 header for lossless round-trips.\n+// Strips disc-level junk and partition-level junk (encrypted sectors whose decrypted\n+// content is zero or LFG padding), records a junk bitmap for reconstruction.\n+// See: https://github.com/dolphin-emu/dolphin/pull/14731\n+bool ConvertToWBFS(BlobReader* infile, const std::string& infile_path,\n+                   const std::string& outfile_path, const CompressCB& callback)\n+{\n+  ASSERT(infile->GetDataSizeType() == DataSizeType::Accurate ||\n+         infile->GetDataSizeType() == DataSizeType::UpperBound);\n+\n+  File::DirectIOFile outfile(outfile_path, File::AccessMode::Write);\n+  if (!outfile.IsOpen())\n+  {\n+    PanicAlertFmtT(\n+        "Failed to open the output file \\"{0}\\".\\n"\n+        "Check that you have permissions to write the target folder and that the media can "\n+        "be written.",\n+        outfile_path);\n+    return false;\n+  }\n+\n+  const u64 disc_size = infile->GetDataSize();\n+\n+  // These match the values used by standard WBFS tools (wwt, WBFS Manager)\n+  static constexpr u8 hd_sector_shift = 9;\n+  static constexpr u8 wbfs_sector_shift = 21;\n+  static constexpr u64 hd_sector_size = 1ull << hd_sector_shift;\n+  static constexpr u64 wbfs_sector_size = 1ull << wbfs_sector_shift;\n+\n+  const u64 blocks_per_disc = (disc_size + wbfs_sector_size - 1) / wbfs_sector_size;\n+  const u64 disc_info_size =\n+      Common::AlignUp(WII_DISC_HEADER_SIZE + blocks_per_disc * sizeof(u16), hd_sector_size);\n+\n+  // Read disc header (first 256 bytes contain disc_id, disc_num, title, etc.)\n+  std::vector<u8> disc_header(WII_DISC_HEADER_SIZE, 0);\n+  if (!infile->Read(0, WII_DISC_HEADER_SIZE, disc_header.data()))\n+  {\n+    PanicAlertFmtT("Failed to read from the input file \\"{0}\\".", infile_path);\n+    return false;\n+  }\n+\n+  // Use Volume for partition info and decrypted reads\n+  struct PartitionInfo\n+  {\n+    u64 data_offset;\n+    u64 data_size;\n+    Partition partition;\n+  };\n+  std::vector<PartitionInfo> partitions;\n+\n+  std::unique_ptr<VolumeDisc> volume = CreateDisc(infile_path);\n+  if (volume)\n+  {\n+    for (const Partition& partition : volume->GetPartitions())\n+    {\n+      const std::optional<u64> data_offset =\n+          volume->ReadSwappedAndShifted(partition.offset + 0x2B8, PARTITION_NONE);\n+      const std::optional<u64> data_size =\n+          volume->ReadSwappedAndShifted(partition.offset + 0x2BC, PARTITION_NONE);\n+      if (!data_offset || !data_size)\n+        continue;\n+\n+      PartitionInfo info;\n+      info.data_offset = partition.offset + *data_offset;\n+      info.data_size = *data_size;\n+      info.partition = partition;\n+      partitions.push_back(info);\n+    }\n+  }\n+\n+  // NKit v2 gap type bitmap: 1 bit per block, MSB-first, always sized for dual-layer\n+  const u64 gap_type_blocks = (DL_DVD_SIZE + wbfs_sector_size - 1) / wbfs_sector_size;\n+  const u64 gap_type_bytes = (gap_type_blocks + 7) / 8;\n+  std::vector<u8> gap_type(gap_type_bytes, 0);\n+\n+  // Compute data_start up front so we can write sectors during the scan\n+  const u64 data_start = Common::AlignUp(hd_sector_size + disc_info_size, wbfs_sector_size);\n+  const u16 wlba_base = static_cast<u16>(data_start / wbfs_sector_size);\n+\n+  // Single pass: scan, classify, hash, and write used sectors in one loop\n+  std::vector<u8> sector_buf(wbfs_sector_size, 0);\n+  std::vector<u16> wlba_table(blocks_per_disc, 0);\n+  u16 used_count = 0;\n+\n+  // NKit v2 stores four hash digests for verification\n+  auto sha1_ctx = Common::SHA1::CreateContext();\n+  u32 crc = Common::StartCRC32();\n+  mbedtls_md5_context md5_ctx{};\n+  mbedtls_md5_init(&md5_ctx);\n+  mbedtls_md5_starts_ret(&md5_ctx);\n+  XXH64_state_t* xxh_state = XXH64_createState();\n+  XXH64_reset(xxh_state, 0);\n+\n+  for (u64 i = 0; i < blocks_per_disc; i++)\n+  {\n+    if (i % 100 == 0)\n+    {\n+      const bool was_cancelled =\n+          !callback(Common::GetStringT("Converting"),\n+                    static_cast<float>(i) / static_cast<float>(blocks_per_disc));\n+      if (was_cancelled)\n+      {\n+        XXH64_freeState(xxh_state);\n+        mbedtls_md5_free(&md5_ctx);\n+        outfile.Close();\n+        File::Delete(outfile_path);\n+        return false;\n+      }\n+    }\n+\n+    const u64 offset = i * wbfs_sector_size;\n+    const size_t sz = static_cast<size_t>(std::min(wbfs_sector_size, disc_size - offset));\n+\n+    if (!infile->Read(offset, sz, sector_buf.data()))\n+    {\n+      PanicAlertFmtT("Failed to read from the input file \\"{0}\\".", infile_path);\n+      XXH64_freeState(xxh_state);\n+      mbedtls_md5_free(&md5_ctx);\n+      outfile.Close();\n+      File::Delete(outfile_path);\n+      return false;\n+    }\n+\n+    // Update all four hashes with the full disc data\n+    sha1_ctx->Update(sector_buf.data(), sz);\n+    crc = Common::UpdateCRC32(crc, sector_buf.data(), sz);\n+    mbedtls_md5_update_ret(&md5_ctx, sector_buf.data(), sz);\n+    XXH64_update(xxh_state, sector_buf.data(), sz);\n+\n+    // Find which partition (if any) this block belongs to\n+    const u32 start_sector = static_cast<u32>(offset / VolumeWii::BLOCK_TOTAL_SIZE);\n+    const u32 end_sector = static_cast<u32>((offset + sz) / VolumeWii::BLOCK_TOTAL_SIZE);\n+    const auto it = std::ranges::find_if(partitions, [&](const PartitionInfo& p) {\n+      const u32 p_start = static_cast<u32>(p.data_offset / VolumeWii::BLOCK_TOTAL_SIZE);\n+      const u32 p_end =\n+          static_cast<u32>((p.data_offset + p.data_size) / VolumeWii::BLOCK_TOTAL_SIZE);\n+      return start_sector >= p_start && end_sector <= p_end;\n+    });\n+    const PartitionInfo* pi = (it != partitions.end()) ? &*it : nullptr;\n+\n+    bool is_used = true;\n+\n+    if (pi)\n+    {\n+      // Partition data: use Volume::Read to get decrypted data for junk/zero checks.\n+      // All-zero and all-junk are checked separately - mixed blocks are stored.\n+      bool all_zero = true;\n+      bool all_junk = true;\n+      for (u64 sub = 0; sub < sz; sub += VolumeWii::BLOCK_TOTAL_SIZE)\n+      {\n+        const u64 abs = offset + sub;\n+        const u64 sector_in_partition = (abs - pi->data_offset) / VolumeWii::BLOCK_TOTAL_SIZE;\n+        const u64 partition_offset = sector_in_partition * VolumeWii::BLOCK_DATA_SIZE;\n+\n+        u8 decrypted[VolumeWii::BLOCK_DATA_SIZE];\n+        if (!volume->Read(partition_offset, VolumeWii::BLOCK_DATA_SIZE, decrypted, pi->partition))\n+          break;\n+\n+        const bool sector_zero = std::ranges::all_of(decrypted, [](u8 b) { return b == 0; });\n+        if (!sector_zero)\n+        {\n+          all_zero = false;\n+          const bool sector_junk = LaggedFibonacciGenerator::IsJunkBlock(\n+              decrypted, VolumeWii::BLOCK_DATA_SIZE, partition_offset, disc_header.data(),\n+              disc_header[6]);\n+          if (!sector_junk)\n+            all_junk = false;\n+        }\n+\n+        if (!all_zero && !all_junk)\n+          break;\n+      }\n+\n+      if (all_zero || all_junk)\n+      {\n+        if (all_junk && !all_zero)\n+          gap_type[i / 8] |= static_cast<u8>(1 << (7 - (i & 7)));\n+        is_used = false;\n+      }\n+    }\n+    else\n+    {\n+      // Non-partition data: check disc-level zero and junk patterns\n+      const bool is_zero = std::ranges::all_of(sector_buf, [](u8 b) { return b == 0; });\n+      if (is_zero)\n+      {\n+        is_used = false;\n+      }\n+      else if (LaggedFibonacciGenerator::IsJunkBlock(sector_buf.data(), sz, offset,\n+                                                     disc_header.data(), disc_header[6]))\n+      {\n+        gap_type[i / 8] |= static_cast<u8>(1 << (7 - (i & 7)));\n+        is_used = false;\n+      }\n+    }\n+\n+    if (is_used)\n+    {\n+      // Write sector directly to output\n+      const u64 out_offset = data_start + static_cast<u64>(used_count) * wbfs_sector_size;\n+      outfile.Seek(out_offset, File::SeekOrigin::Begin);\n+      std::fill(sector_buf.begin() + sz, sector_buf.end(), u8{0});\n+      if (!outfile.Write(sector_buf.data(), wbfs_sector_size))\n+      {\n+        PanicAlertFmtT("Failed to write the output file \\"{0}\\".\\n"\n+                       "Check that you have enough space available on the target drive.",\n+                       outfile_path);\n+        XXH64_freeState(xxh_state);\n+        mbedtls_md5_free(&md5_ctx);\n+        outfile.Close();\n+        File::Delete(outfile_path);\n+        return false;\n+      }\n+\n+      wlba_table[i] = Common::swap16(static_cast<u16>(wlba_base + used_count));\n+      used_count++;\n+    }\n+  }\n+\n+  // Finalize hashes\n+  const Common::SHA1::Digest sha1_digest = sha1_ctx->Finish();\n+  const u64 xxh_digest = XXH64_digest(xxh_state);\n+  XXH64_freeState(xxh_state);\n+\n+  // Write WBFS header (seek back to start)\n+  const u64 total_size = data_start + static_cast<u64>(used_count) * wbfs_sector_size;\n+  const u32 hd_sector_count = static_cast<u32>(total_size / hd_sector_size);\n+\n+  WbfsHeader header{};\n+  header.magic = WBFS_MAGIC;\n+  header.hd_sector_count = Common::swap32(hd_sector_count);\n+  header.hd_sector_shift = hd_sector_shift;\n+  header.wbfs_sector_shift = wbfs_sector_shift;\n+  header.disc_table[0] = 1;\n+\n+  outfile.Seek(0, File::SeekOrigin::Begin);\n+  if (!outfile.Write(Common::AsU8Span(header)))\n+  {\n+    PanicAlertFmtT("Failed to write the output file \\"{0}\\".\\n"\n+                   "Check that you have enough space available on the target drive.",\n+                   outfile_path);\n+    outfile.Close();\n+    File::Delete(outfile_path);\n+    return false;\n+  }', 'path': 'Source/Core/DiscIO/WbfsBlob.cpp', 'position': 540, 'original_position': 540, 'commit_id': '24b41d58df2315831b74f76b95417f2739d02f9d', 'user': {'login': 'phire', 'id': 138484, 'node_id': 'MDQ6VXNlcjEzODQ4NA==', 'avatar_url': 'https://avatars.githubusercontent.com/u/138484?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/phire', 'html_url': 'https://github.com/phire', 'followers_url': 'https://api.github.com/users/phire/followers', 'following_url': 'https://api.github.com/users/phire/following{/other_user}', 'gists_url': 'https://api.github.com/users/phire/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/phire/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/phire/subscriptions', 'organizations_url': 'https://api.github.com/users/phire/orgs', 'repos_url': 'https://api.github.com/users/phire/repos', 'events_url': 'https://api.github.com/users/phire/events{/privacy}', 'received_events_url': 'https://api.github.com/users/phire/received_events', 'type': 'User', 'user_view_type': 'public', 'site_admin': False}, 'body': 'I think this is the job for a lambda.\n\nPut this near the top of the function:\n\n```c++\nauto write_failed_panic [&] {\n  PanicAlertFmtT("Failed to write..... \n  return false;\n};\n```\n\nWhen combined with `Common::ScopeGuard` to handle closing/deleting (as discussed above), you should be able to simplify all these down to:\n\n```c++\nif (!outfile.Write(Common::AsU8Span(header)))\n{\n  return write_failed_panic();\n}\n```', 'created_at': '2026-07-18T22:18:18Z', 'updated_at': '2026-07-18T22:26:23Z', 'html_url': 'https://github.com/dolphin-emu/dolphin/pull/14731#discussion_r3609296950', 'pull_request_url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/14731', 'author_association': 'MEMBER', '_links': {'self': {'href': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/comments/3609296950'}, 'html': {'href': 'https://github.com/dolphin-emu/dolphin/pull/14731#discussion_r3609296950'}, 'pull_request': {'href': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/14731'}}, 'original_commit_id': '24b41d58df2315831b74f76b95417f2739d02f9d', 'reactions': {'url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/comments/3609296950/reactions', 'total_count': 0, '+1': 0, '-1': 0, 'laugh': 0, 'hooray': 0, 'confused': 0, 'heart': 0, 'rocket': 0, 'eyes': 0}}], 'type': 'gh_pull_request_review'}
2026-07-18T22:26:25.289800	{'source': 'ghhookparser', 'repo': 'dolphin-emu/dolphin', 'author': 'phire', 'action': 'edited', 'pr_id': 14731, 'pr_title': 'Convert To WBFS Support', 'state': 'commented', 'url': 'https://github.com/dolphin-emu/dolphin/pull/14731#pullrequestreview-4729322283', 'comments': [{'id': 3609218797, 'node_id': 'PRRC_kwDOALCn2M7XIE7t', 'url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/comments/3609218797', 'pull_request_review_id': 4729322283, 'diff_hunk': '@@ -119,22 +144,191 @@ bool WbfsFileReader::ReadHeader()\n   return m_header.disc_table[0] != 0;\n }\n \n+bool WbfsFileReader::ReadNKitHeader()\n+{\n+  const u64 gap_type_blocks = (DL_DVD_SIZE + m_wbfs_sector_size - 1) / m_wbfs_sector_size;\n+  m_nkit_info = NKit::ReadHeaderFromFile(m_files[0].file, NKit::HEADER_OFFSET, gap_type_blocks);\n+  if (!m_nkit_info.valid)\n+    return false;\n+\n+  m_has_nkit_header = true;\n+  return true;\n+}\n+\n+bool WbfsFileReader::IsBlockStored(u64 block_index) const\n+{\n+  return block_index < m_blocks_per_disc && m_wlba_table[block_index] != 0;\n+}\n+\n+bool WbfsFileReader::IsGapJunk(u64 block_index) const\n+{\n+  return NKit::IsGapJunk(m_nkit_info.gap_type, block_index);\n+}\n+\n+void WbfsFileReader::GenerateJunkData(u64 disc_offset, u64 size, u8* out) const', 'path': 'Source/Core/DiscIO/WbfsBlob.cpp', 'position': 112, 'original_position': 112, 'commit_id': '24b41d58df2315831b74f76b95417f2739d02f9d', 'user': {'login': 'phire', 'id': 138484, 'node_id': 'MDQ6VXNlcjEzODQ4NA==', 'avatar_url': 'https://avatars.githubusercontent.com/u/138484?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/phire', 'html_url': 'https://github.com/phire', 'followers_url': 'https://api.github.com/users/phire/followers', 'following_url': 'https://api.github.com/users/phire/following{/other_user}', 'gists_url': 'https://api.github.com/users/phire/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/phire/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/phire/subscriptions', 'organizations_url': 'https://api.github.com/users/phire/orgs', 'repos_url': 'https://api.github.com/users/phire/repos', 'events_url': 'https://api.github.com/users/phire/events{/privacy}', 'received_events_url': 'https://api.github.com/users/phire/received_events', 'type': 'User', 'user_view_type': 'public', 'site_admin': False}, 'body': 'Can replace size/out with a `std::span` (same with FillJunkData) ', 'created_at': '2026-07-18T21:23:14Z', 'updated_at': '2026-07-18T22:26:23Z', 'html_url': 'https://github.com/dolphin-emu/dolphin/pull/14731#discussion_r3609218797', 'pull_request_url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/14731', 'author_association': 'MEMBER', '_links': {'self': {'href': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/comments/3609218797'}, 'html': {'href': 'https://github.com/dolphin-emu/dolphin/pull/14731#discussion_r3609218797'}, 'pull_request': {'href': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/14731'}}, 'original_commit_id': '24b41d58df2315831b74f76b95417f2739d02f9d', 'reactions': {'url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/comments/3609218797/reactions', 'total_count': 0, '+1': 0, '-1': 0, 'laugh': 0, 'hooray': 0, 'confused': 0, 'heart': 0, 'rocket': 0, 'eyes': 0}}, {'id': 3609251889, 'node_id': 'PRRC_kwDOALCn2M7XINAx', 'url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/comments/3609251889', 'pull_request_review_id': 4729322283, 'diff_hunk': '@@ -186,7 +380,304 @@ std::unique_ptr<WbfsFileReader> WbfsFileReader::Create(File::DirectIOFile file,\n   if (!reader->IsGood())\n     reader.reset();\n \n+  if (reader && reader->m_has_nkit_header)\n+    reader->ReadPartitionInfo();\n+\n   return reader;\n }\n \n+// Converts any disc image to WBFS with an NKit v2 header for lossless round-trips.\n+// Strips disc-level junk and partition-level junk (encrypted sectors whose decrypted\n+// content is zero or LFG padding), records a junk bitmap for reconstruction.\n+// See: https://github.com/dolphin-emu/dolphin/pull/14731\n+bool ConvertToWBFS(BlobReader* infile, const std::string& infile_path,\n+                   const std::string& outfile_path, const CompressCB& callback)\n+{\n+  ASSERT(infile->GetDataSizeType() == DataSizeType::Accurate ||\n+         infile->GetDataSizeType() == DataSizeType::UpperBound);\n+\n+  File::DirectIOFile outfile(outfile_path, File::AccessMode::Write);\n+  if (!outfile.IsOpen())\n+  {\n+    PanicAlertFmtT(\n+        "Failed to open the output file \\"{0}\\".\\n"\n+        "Check that you have permissions to write the target folder and that the media can "\n+        "be written.",\n+        outfile_path);\n+    return false;\n+  }\n+\n+  const u64 disc_size = infile->GetDataSize();\n+\n+  // These match the values used by standard WBFS tools (wwt, WBFS Manager)\n+  static constexpr u8 hd_sector_shift = 9;\n+  static constexpr u8 wbfs_sector_shift = 21;\n+  static constexpr u64 hd_sector_size = 1ull << hd_sector_shift;\n+  static constexpr u64 wbfs_sector_size = 1ull << wbfs_sector_shift;\n+\n+  const u64 blocks_per_disc = (disc_size + wbfs_sector_size - 1) / wbfs_sector_size;\n+  const u64 disc_info_size =\n+      Common::AlignUp(WII_DISC_HEADER_SIZE + blocks_per_disc * sizeof(u16), hd_sector_size);\n+\n+  // Read disc header (first 256 bytes contain disc_id, disc_num, title, etc.)\n+  std::vector<u8> disc_header(WII_DISC_HEADER_SIZE, 0);\n+  if (!infile->Read(0, WII_DISC_HEADER_SIZE, disc_header.data()))\n+  {\n+    PanicAlertFmtT("Failed to read from the input file \\"{0}\\".", infile_path);\n+    return false;\n+  }\n+\n+  // Use Volume for partition info and decrypted reads\n+  struct PartitionInfo\n+  {\n+    u64 data_offset;\n+    u64 data_size;\n+    Partition partition;\n+  };\n+  std::vector<PartitionInfo> partitions;\n+\n+  std::unique_ptr<VolumeDisc> volume = CreateDisc(infile_path);\n+  if (volume)\n+  {\n+    for (const Partition& partition : volume->GetPartitions())\n+    {\n+      const std::optional<u64> data_offset =\n+          volume->ReadSwappedAndShifted(partition.offset + 0x2B8, PARTITION_NONE);\n+      const std::optional<u64> data_size =\n+          volume->ReadSwappedAndShifted(partition.offset + 0x2BC, PARTITION_NONE);\n+      if (!data_offset || !data_size)\n+        continue;\n+\n+      PartitionInfo info;\n+      info.data_offset = partition.offset + *data_offset;\n+      info.data_size = *data_size;\n+      info.partition = partition;\n+      partitions.push_back(info);\n+    }\n+  }\n+\n+  // NKit v2 gap type bitmap: 1 bit per block, MSB-first, always sized for dual-layer\n+  const u64 gap_type_blocks = (DL_DVD_SIZE + wbfs_sector_size - 1) / wbfs_sector_size;\n+  const u64 gap_type_bytes = (gap_type_blocks + 7) / 8;\n+  std::vector<u8> gap_type(gap_type_bytes, 0);\n+\n+  // Compute data_start up front so we can write sectors during the scan\n+  const u64 data_start = Common::AlignUp(hd_sector_size + disc_info_size, wbfs_sector_size);\n+  const u16 wlba_base = static_cast<u16>(data_start / wbfs_sector_size);\n+\n+  // Single pass: scan, classify, hash, and write used sectors in one loop\n+  std::vector<u8> sector_buf(wbfs_sector_size, 0);\n+  std::vector<u16> wlba_table(blocks_per_disc, 0);\n+  u16 used_count = 0;\n+\n+  // NKit v2 stores four hash digests for verification\n+  auto sha1_ctx = Common::SHA1::CreateContext();\n+  u32 crc = Common::StartCRC32();\n+  mbedtls_md5_context md5_ctx{};\n+  mbedtls_md5_init(&md5_ctx);\n+  mbedtls_md5_starts_ret(&md5_ctx);\n+  XXH64_state_t* xxh_state = XXH64_createState();\n+  XXH64_reset(xxh_state, 0);\n+\n+  for (u64 i = 0; i < blocks_per_disc; i++)\n+  {\n+    if (i % 100 == 0)\n+    {\n+      const bool was_cancelled =\n+          !callback(Common::GetStringT("Converting"),\n+                    static_cast<float>(i) / static_cast<float>(blocks_per_disc));\n+      if (was_cancelled)\n+      {\n+        XXH64_freeState(xxh_state);\n+        mbedtls_md5_free(&md5_ctx);\n+        outfile.Close();\n+        File::Delete(outfile_path);\n+        return false;\n+      }\n+    }\n+\n+    const u64 offset = i * wbfs_sector_size;\n+    const size_t sz = static_cast<size_t>(std::min(wbfs_sector_size, disc_size - offset));\n+\n+    if (!infile->Read(offset, sz, sector_buf.data()))', 'path': 'Source/Core/DiscIO/WbfsBlob.cpp', 'position': 409, 'original_position': 409, 'commit_id': '24b41d58df2315831b74f76b95417f2739d02f9d', 'user': {'login': 'phire', 'id': 138484, 'node_id': 'MDQ6VXNlcjEzODQ4NA==', 'avatar_url': 'https://avatars.githubusercontent.com/u/138484?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/phire', 'html_url': 'https://github.com/phire', 'followers_url': 'https://api.github.com/users/phire/followers', 'following_url': 'https://api.github.com/users/phire/following{/other_user}', 'gists_url': 'https://api.github.com/users/phire/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/phire/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/phire/subscriptions', 'organizations_url': 'https://api.github.com/users/phire/orgs', 'repos_url': 'https://api.github.com/users/phire/repos', 'events_url': 'https://api.github.com/users/phire/events{/privacy}', 'received_events_url': 'https://api.github.com/users/phire/received_events', 'type': 'User', 'user_view_type': 'public', 'site_admin': False}, 'body': "Don't read here. \nIf the sector is in a partition and is either junk or zeros, there is no need to fetch the encrypted version. That's just going to trigger an unnecessary encrypt operation for RVZ/WIA inputs.\n\nOnce we discover the sector is outside a partition, or contains data, then we can read/encrypt it. ", 'created_at': '2026-07-18T21:46:22Z', 'updated_at': '2026-07-18T22:26:23Z', 'html_url': 'https://github.com/dolphin-emu/dolphin/pull/14731#discussion_r3609251889', 'pull_request_url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/14731', 'author_association': 'MEMBER', '_links': {'self': {'href': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/comments/3609251889'}, 'html': {'href': 'https://github.com/dolphin-emu/dolphin/pull/14731#discussion_r3609251889'}, 'pull_request': {'href': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/14731'}}, 'original_commit_id': '24b41d58df2315831b74f76b95417f2739d02f9d', 'reactions': {'url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/comments/3609251889/reactions', 'total_count': 0, '+1': 0, '-1': 0, 'laugh': 0, 'hooray': 0, 'confused': 0, 'heart': 0, 'rocket': 0, 'eyes': 0}}, {'id': 3609258421, 'node_id': 'PRRC_kwDOALCn2M7XIOm1', 'url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/comments/3609258421', 'pull_request_review_id': 4729322283, 'diff_hunk': '@@ -186,7 +380,304 @@ std::unique_ptr<WbfsFileReader> WbfsFileReader::Create(File::DirectIOFile file,\n   if (!reader->IsGood())\n     reader.reset();\n \n+  if (reader && reader->m_has_nkit_header)\n+    reader->ReadPartitionInfo();\n+\n   return reader;\n }\n \n+// Converts any disc image to WBFS with an NKit v2 header for lossless round-trips.\n+// Strips disc-level junk and partition-level junk (encrypted sectors whose decrypted\n+// content is zero or LFG padding), records a junk bitmap for reconstruction.\n+// See: https://github.com/dolphin-emu/dolphin/pull/14731\n+bool ConvertToWBFS(BlobReader* infile, const std::string& infile_path,\n+                   const std::string& outfile_path, const CompressCB& callback)\n+{\n+  ASSERT(infile->GetDataSizeType() == DataSizeType::Accurate ||\n+         infile->GetDataSizeType() == DataSizeType::UpperBound);\n+\n+  File::DirectIOFile outfile(outfile_path, File::AccessMode::Write);\n+  if (!outfile.IsOpen())\n+  {\n+    PanicAlertFmtT(\n+        "Failed to open the output file \\"{0}\\".\\n"\n+        "Check that you have permissions to write the target folder and that the media can "\n+        "be written.",\n+        outfile_path);\n+    return false;\n+  }\n+\n+  const u64 disc_size = infile->GetDataSize();\n+\n+  // These match the values used by standard WBFS tools (wwt, WBFS Manager)\n+  static constexpr u8 hd_sector_shift = 9;\n+  static constexpr u8 wbfs_sector_shift = 21;\n+  static constexpr u64 hd_sector_size = 1ull << hd_sector_shift;\n+  static constexpr u64 wbfs_sector_size = 1ull << wbfs_sector_shift;\n+\n+  const u64 blocks_per_disc = (disc_size + wbfs_sector_size - 1) / wbfs_sector_size;\n+  const u64 disc_info_size =\n+      Common::AlignUp(WII_DISC_HEADER_SIZE + blocks_per_disc * sizeof(u16), hd_sector_size);\n+\n+  // Read disc header (first 256 bytes contain disc_id, disc_num, title, etc.)\n+  std::vector<u8> disc_header(WII_DISC_HEADER_SIZE, 0);\n+  if (!infile->Read(0, WII_DISC_HEADER_SIZE, disc_header.data()))\n+  {\n+    PanicAlertFmtT("Failed to read from the input file \\"{0}\\".", infile_path);\n+    return false;\n+  }\n+\n+  // Use Volume for partition info and decrypted reads\n+  struct PartitionInfo\n+  {\n+    u64 data_offset;\n+    u64 data_size;\n+    Partition partition;\n+  };\n+  std::vector<PartitionInfo> partitions;\n+\n+  std::unique_ptr<VolumeDisc> volume = CreateDisc(infile_path);\n+  if (volume)\n+  {\n+    for (const Partition& partition : volume->GetPartitions())\n+    {\n+      const std::optional<u64> data_offset =\n+          volume->ReadSwappedAndShifted(partition.offset + 0x2B8, PARTITION_NONE);\n+      const std::optional<u64> data_size =\n+          volume->ReadSwappedAndShifted(partition.offset + 0x2BC, PARTITION_NONE);\n+      if (!data_offset || !data_size)\n+        continue;\n+\n+      PartitionInfo info;\n+      info.data_offset = partition.offset + *data_offset;\n+      info.data_size = *data_size;\n+      info.partition = partition;\n+      partitions.push_back(info);\n+    }\n+  }\n+\n+  // NKit v2 gap type bitmap: 1 bit per block, MSB-first, always sized for dual-layer\n+  const u64 gap_type_blocks = (DL_DVD_SIZE + wbfs_sector_size - 1) / wbfs_sector_size;\n+  const u64 gap_type_bytes = (gap_type_blocks + 7) / 8;\n+  std::vector<u8> gap_type(gap_type_bytes, 0);\n+\n+  // Compute data_start up front so we can write sectors during the scan\n+  const u64 data_start = Common::AlignUp(hd_sector_size + disc_info_size, wbfs_sector_size);\n+  const u16 wlba_base = static_cast<u16>(data_start / wbfs_sector_size);\n+\n+  // Single pass: scan, classify, hash, and write used sectors in one loop\n+  std::vector<u8> sector_buf(wbfs_sector_size, 0);\n+  std::vector<u16> wlba_table(blocks_per_disc, 0);\n+  u16 used_count = 0;\n+\n+  // NKit v2 stores four hash digests for verification\n+  auto sha1_ctx = Common::SHA1::CreateContext();\n+  u32 crc = Common::StartCRC32();\n+  mbedtls_md5_context md5_ctx{};\n+  mbedtls_md5_init(&md5_ctx);\n+  mbedtls_md5_starts_ret(&md5_ctx);\n+  XXH64_state_t* xxh_state = XXH64_createState();\n+  XXH64_reset(xxh_state, 0);\n+\n+  for (u64 i = 0; i < blocks_per_disc; i++)\n+  {\n+    if (i % 100 == 0)\n+    {\n+      const bool was_cancelled =\n+          !callback(Common::GetStringT("Converting"),\n+                    static_cast<float>(i) / static_cast<float>(blocks_per_disc));\n+      if (was_cancelled)\n+      {\n+        XXH64_freeState(xxh_state);\n+        mbedtls_md5_free(&md5_ctx);\n+        outfile.Close();\n+        File::Delete(outfile_path);\n+        return false;\n+      }\n+    }\n+\n+    const u64 offset = i * wbfs_sector_size;\n+    const size_t sz = static_cast<size_t>(std::min(wbfs_sector_size, disc_size - offset));\n+\n+    if (!infile->Read(offset, sz, sector_buf.data()))\n+    {\n+      PanicAlertFmtT("Failed to read from the input file \\"{0}\\".", infile_path);\n+      XXH64_freeState(xxh_state);\n+      mbedtls_md5_free(&md5_ctx);\n+      outfile.Close();\n+      File::Delete(outfile_path);\n+      return false;\n+    }\n+\n+    // Update all four hashes with the full disc data\n+    sha1_ctx->Update(sector_buf.data(), sz);\n+    crc = Common::UpdateCRC32(crc, sector_buf.data(), sz);\n+    mbedtls_md5_update_ret(&md5_ctx, sector_buf.data(), sz);\n+    XXH64_update(xxh_state, sector_buf.data(), sz);\n+\n+    // Find which partition (if any) this block belongs to\n+    const u32 start_sector = static_cast<u32>(offset / VolumeWii::BLOCK_TOTAL_SIZE);\n+    const u32 end_sector = static_cast<u32>((offset + sz) / VolumeWii::BLOCK_TOTAL_SIZE);\n+    const auto it = std::ranges::find_if(partitions, [&](const PartitionInfo& p) {\n+      const u32 p_start = static_cast<u32>(p.data_offset / VolumeWii::BLOCK_TOTAL_SIZE);\n+      const u32 p_end =\n+          static_cast<u32>((p.data_offset + p.data_size) / VolumeWii::BLOCK_TOTAL_SIZE);\n+      return start_sector >= p_start && end_sector <= p_end;\n+    });\n+    const PartitionInfo* pi = (it != partitions.end()) ? &*it : nullptr;\n+\n+    bool is_used = true;\n+\n+    if (pi)', 'path': 'Source/Core/DiscIO/WbfsBlob.cpp', 'position': 438, 'original_position': 438, 'commit_id': '24b41d58df2315831b74f76b95417f2739d02f9d', 'user': {'login': 'phire', 'id': 138484, 'node_id': 'MDQ6VXNlcjEzODQ4NA==', 'avatar_url': 'https://avatars.githubusercontent.com/u/138484?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/phire', 'html_url': 'https://github.com/phire', 'followers_url': 'https://api.github.com/users/phire/followers', 'following_url': 'https://api.github.com/users/phire/following{/other_user}', 'gists_url': 'https://api.github.com/users/phire/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/phire/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/phire/subscriptions', 'organizations_url': 'https://api.github.com/users/phire/orgs', 'repos_url': 'https://api.github.com/users/phire/repos', 'events_url': 'https://api.github.com/users/phire/events{/privacy}', 'received_events_url': 'https://api.github.com/users/phire/received_events', 'type': 'User', 'user_view_type': 'public', 'site_admin': False}, 'body': 'Put the result of `find_if` directly into pi\n\nThen you can skip the weird conversion to nullptr and do the check here\n\n```suggestion\n    if (pi != partitions.end())\n```', 'created_at': '2026-07-18T21:51:02Z', 'updated_at': '2026-07-18T22:26:23Z', 'html_url': 'https://github.com/dolphin-emu/dolphin/pull/14731#discussion_r3609258421', 'pull_request_url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/14731', 'author_association': 'MEMBER', '_links': {'self': {'href': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/comments/3609258421'}, 'html': {'href': 'https://github.com/dolphin-emu/dolphin/pull/14731#discussion_r3609258421'}, 'pull_request': {'href': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/14731'}}, 'original_commit_id': '24b41d58df2315831b74f76b95417f2739d02f9d', 'reactions': {'url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/comments/3609258421/reactions', 'total_count': 0, '+1': 0, '-1': 0, 'laugh': 0, 'hooray': 0, 'confused': 0, 'heart': 0, 'rocket': 0, 'eyes': 0}}, {'id': 3609262932, 'node_id': 'PRRC_kwDOALCn2M7XIPtU', 'url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/comments/3609262932', 'pull_request_review_id': 4729322283, 'diff_hunk': '@@ -186,7 +380,304 @@ std::unique_ptr<WbfsFileReader> WbfsFileReader::Create(File::DirectIOFile file,\n   if (!reader->IsGood())\n     reader.reset();\n \n+  if (reader && reader->m_has_nkit_header)\n+    reader->ReadPartitionInfo();\n+\n   return reader;\n }\n \n+// Converts any disc image to WBFS with an NKit v2 header for lossless round-trips.\n+// Strips disc-level junk and partition-level junk (encrypted sectors whose decrypted\n+// content is zero or LFG padding), records a junk bitmap for reconstruction.\n+// See: https://github.com/dolphin-emu/dolphin/pull/14731\n+bool ConvertToWBFS(BlobReader* infile, const std::string& infile_path,\n+                   const std::string& outfile_path, const CompressCB& callback)\n+{\n+  ASSERT(infile->GetDataSizeType() == DataSizeType::Accurate ||\n+         infile->GetDataSizeType() == DataSizeType::UpperBound);\n+\n+  File::DirectIOFile outfile(outfile_path, File::AccessMode::Write);\n+  if (!outfile.IsOpen())\n+  {\n+    PanicAlertFmtT(\n+        "Failed to open the output file \\"{0}\\".\\n"\n+        "Check that you have permissions to write the target folder and that the media can "\n+        "be written.",\n+        outfile_path);\n+    return false;\n+  }\n+\n+  const u64 disc_size = infile->GetDataSize();\n+\n+  // These match the values used by standard WBFS tools (wwt, WBFS Manager)\n+  static constexpr u8 hd_sector_shift = 9;\n+  static constexpr u8 wbfs_sector_shift = 21;\n+  static constexpr u64 hd_sector_size = 1ull << hd_sector_shift;\n+  static constexpr u64 wbfs_sector_size = 1ull << wbfs_sector_shift;\n+\n+  const u64 blocks_per_disc = (disc_size + wbfs_sector_size - 1) / wbfs_sector_size;\n+  const u64 disc_info_size =\n+      Common::AlignUp(WII_DISC_HEADER_SIZE + blocks_per_disc * sizeof(u16), hd_sector_size);\n+\n+  // Read disc header (first 256 bytes contain disc_id, disc_num, title, etc.)\n+  std::vector<u8> disc_header(WII_DISC_HEADER_SIZE, 0);\n+  if (!infile->Read(0, WII_DISC_HEADER_SIZE, disc_header.data()))\n+  {\n+    PanicAlertFmtT("Failed to read from the input file \\"{0}\\".", infile_path);\n+    return false;\n+  }\n+\n+  // Use Volume for partition info and decrypted reads\n+  struct PartitionInfo\n+  {\n+    u64 data_offset;\n+    u64 data_size;\n+    Partition partition;\n+  };\n+  std::vector<PartitionInfo> partitions;\n+\n+  std::unique_ptr<VolumeDisc> volume = CreateDisc(infile_path);\n+  if (volume)\n+  {\n+    for (const Partition& partition : volume->GetPartitions())\n+    {\n+      const std::optional<u64> data_offset =\n+          volume->ReadSwappedAndShifted(partition.offset + 0x2B8, PARTITION_NONE);\n+      const std::optional<u64> data_size =\n+          volume->ReadSwappedAndShifted(partition.offset + 0x2BC, PARTITION_NONE);\n+      if (!data_offset || !data_size)\n+        continue;\n+\n+      PartitionInfo info;\n+      info.data_offset = partition.offset + *data_offset;\n+      info.data_size = *data_size;\n+      info.partition = partition;\n+      partitions.push_back(info);\n+    }\n+  }\n+\n+  // NKit v2 gap type bitmap: 1 bit per block, MSB-first, always sized for dual-layer\n+  const u64 gap_type_blocks = (DL_DVD_SIZE + wbfs_sector_size - 1) / wbfs_sector_size;\n+  const u64 gap_type_bytes = (gap_type_blocks + 7) / 8;\n+  std::vector<u8> gap_type(gap_type_bytes, 0);\n+\n+  // Compute data_start up front so we can write sectors during the scan\n+  const u64 data_start = Common::AlignUp(hd_sector_size + disc_info_size, wbfs_sector_size);\n+  const u16 wlba_base = static_cast<u16>(data_start / wbfs_sector_size);\n+\n+  // Single pass: scan, classify, hash, and write used sectors in one loop\n+  std::vector<u8> sector_buf(wbfs_sector_size, 0);\n+  std::vector<u16> wlba_table(blocks_per_disc, 0);\n+  u16 used_count = 0;\n+\n+  // NKit v2 stores four hash digests for verification\n+  auto sha1_ctx = Common::SHA1::CreateContext();\n+  u32 crc = Common::StartCRC32();\n+  mbedtls_md5_context md5_ctx{};\n+  mbedtls_md5_init(&md5_ctx);\n+  mbedtls_md5_starts_ret(&md5_ctx);\n+  XXH64_state_t* xxh_state = XXH64_createState();\n+  XXH64_reset(xxh_state, 0);\n+\n+  for (u64 i = 0; i < blocks_per_disc; i++)\n+  {\n+    if (i % 100 == 0)\n+    {\n+      const bool was_cancelled =\n+          !callback(Common::GetStringT("Converting"),\n+                    static_cast<float>(i) / static_cast<float>(blocks_per_disc));\n+      if (was_cancelled)\n+      {\n+        XXH64_freeState(xxh_state);\n+        mbedtls_md5_free(&md5_ctx);\n+        outfile.Close();\n+        File::Delete(outfile_path);\n+        return false;\n+      }\n+    }\n+\n+    const u64 offset = i * wbfs_sector_size;\n+    const size_t sz = static_cast<size_t>(std::min(wbfs_sector_size, disc_size - offset));\n+\n+    if (!infile->Read(offset, sz, sector_buf.data()))\n+    {\n+      PanicAlertFmtT("Failed to read from the input file \\"{0}\\".", infile_path);\n+      XXH64_freeState(xxh_state);\n+      mbedtls_md5_free(&md5_ctx);\n+      outfile.Close();\n+      File::Delete(outfile_path);\n+      return false;\n+    }\n+\n+    // Update all four hashes with the full disc data\n+    sha1_ctx->Update(sector_buf.data(), sz);\n+    crc = Common::UpdateCRC32(crc, sector_buf.data(), sz);\n+    mbedtls_md5_update_ret(&md5_ctx, sector_buf.data(), sz);\n+    XXH64_update(xxh_state, sector_buf.data(), sz);\n+\n+    // Find which partition (if any) this block belongs to\n+    const u32 start_sector = static_cast<u32>(offset / VolumeWii::BLOCK_TOTAL_SIZE);\n+    const u32 end_sector = static_cast<u32>((offset + sz) / VolumeWii::BLOCK_TOTAL_SIZE);\n+    const auto it = std::ranges::find_if(partitions, [&](const PartitionInfo& p) {\n+      const u32 p_start = static_cast<u32>(p.data_offset / VolumeWii::BLOCK_TOTAL_SIZE);\n+      const u32 p_end =\n+          static_cast<u32>((p.data_offset + p.data_size) / VolumeWii::BLOCK_TOTAL_SIZE);\n+      return start_sector >= p_start && end_sector <= p_end;\n+    });\n+    const PartitionInfo* pi = (it != partitions.end()) ? &*it : nullptr;\n+\n+    bool is_used = true;\n+\n+    if (pi)\n+    {\n+      // Partition data: use Volume::Read to get decrypted data for junk/zero checks.\n+      // All-zero and all-junk are checked separately - mixed blocks are stored.\n+      bool all_zero = true;\n+      bool all_junk = true;\n+      for (u64 sub = 0; sub < sz; sub += VolumeWii::BLOCK_TOTAL_SIZE)\n+      {\n+        const u64 abs = offset + sub;\n+        const u64 sector_in_partition = (abs - pi->data_offset) / VolumeWii::BLOCK_TOTAL_SIZE;\n+        const u64 partition_offset = sector_in_partition * VolumeWii::BLOCK_DATA_SIZE;\n+\n+        u8 decrypted[VolumeWii::BLOCK_DATA_SIZE];\n+        if (!volume->Read(partition_offset, VolumeWii::BLOCK_DATA_SIZE, decrypted, pi->partition))\n+          break;\n+\n+        const bool sector_zero = std::ranges::all_of(decrypted, [](u8 b) { return b == 0; });\n+        if (!sector_zero)\n+        {\n+          all_zero = false;\n+          const bool sector_junk = LaggedFibonacciGenerator::IsJunkBlock(\n+              decrypted, VolumeWii::BLOCK_DATA_SIZE, partition_offset, disc_header.data(),\n+              disc_header[6]);\n+          if (!sector_junk)\n+            all_junk = false;\n+        }\n+\n+        if (!all_zero && !all_junk)\n+          break;\n+      }\n+\n+      if (all_zero || all_junk)\n+      {\n+        if (all_junk && !all_zero)\n+          gap_type[i / 8] |= static_cast<u8>(1 << (7 - (i & 7)));\n+        is_used = false;\n+      }\n+    }\n+    else\n+    {\n+      // Non-partition data: check disc-level zero and junk patterns\n+      const bool is_zero = std::ranges::all_of(sector_buf, [](u8 b) { return b == 0; });\n+      if (is_zero)\n+      {\n+        is_used = false;\n+      }\n+      else if (LaggedFibonacciGenerator::IsJunkBlock(sector_buf.data(), sz, offset,\n+                                                     disc_header.data(), disc_header[6]))\n+      {\n+        gap_type[i / 8] |= static_cast<u8>(1 << (7 - (i & 7)));\n+        is_used = false;\n+      }\n+    }\n+\n+    if (is_used)\n+    {\n+      // Write sector directly to output\n+      const u64 out_offset = data_start + static_cast<u64>(used_count) * wbfs_sector_size;\n+      outfile.Seek(out_offset, File::SeekOrigin::Begin);', 'path': 'Source/Core/DiscIO/WbfsBlob.cpp', 'position': 496, 'original_position': 496, 'commit_id': '24b41d58df2315831b74f76b95417f2739d02f9d', 'user': {'login': 'phire', 'id': 138484, 'node_id': 'MDQ6VXNlcjEzODQ4NA==', 'avatar_url': 'https://avatars.githubusercontent.com/u/138484?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/phire', 'html_url': 'https://github.com/phire', 'followers_url': 'https://api.github.com/users/phire/followers', 'following_url': 'https://api.github.com/users/phire/following{/other_user}', 'gists_url': 'https://api.github.com/users/phire/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/phire/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/phire/subscriptions', 'organizations_url': 'https://api.github.com/users/phire/orgs', 'repos_url': 'https://api.github.com/users/phire/repos', 'events_url': 'https://api.github.com/users/phire/events{/privacy}', 'received_events_url': 'https://api.github.com/users/phire/received_events', 'type': 'User', 'user_view_type': 'public', 'site_admin': False}, 'body': 'Should be able to avoid the seek in the loop.\nJust seek once to `data_start` before the loop, the writes will advance to the next position.  ', 'created_at': '2026-07-18T21:54:25Z', 'updated_at': '2026-07-18T22:26:23Z', 'html_url': 'https://github.com/dolphin-emu/dolphin/pull/14731#discussion_r3609262932', 'pull_request_url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/14731', 'author_association': 'MEMBER', '_links': {'self': {'href': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/comments/3609262932'}, 'html': {'href': 'https://github.com/dolphin-emu/dolphin/pull/14731#discussion_r3609262932'}, 'pull_request': {'href': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/14731'}}, 'original_commit_id': '24b41d58df2315831b74f76b95417f2739d02f9d', 'reactions': {'url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/comments/3609262932/reactions', 'total_count': 0, '+1': 0, '-1': 0, 'laugh': 0, 'hooray': 0, 'confused': 0, 'heart': 0, 'rocket': 0, 'eyes': 0}}, {'id': 3609268698, 'node_id': 'PRRC_kwDOALCn2M7XIRHa', 'url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/comments/3609268698', 'pull_request_review_id': 4729322283, 'diff_hunk': '@@ -186,7 +380,304 @@ std::unique_ptr<WbfsFileReader> WbfsFileReader::Create(File::DirectIOFile file,\n   if (!reader->IsGood())\n     reader.reset();\n \n+  if (reader && reader->m_has_nkit_header)\n+    reader->ReadPartitionInfo();\n+\n   return reader;\n }\n \n+// Converts any disc image to WBFS with an NKit v2 header for lossless round-trips.\n+// Strips disc-level junk and partition-level junk (encrypted sectors whose decrypted\n+// content is zero or LFG padding), records a junk bitmap for reconstruction.\n+// See: https://github.com/dolphin-emu/dolphin/pull/14731\n+bool ConvertToWBFS(BlobReader* infile, const std::string& infile_path,\n+                   const std::string& outfile_path, const CompressCB& callback)\n+{\n+  ASSERT(infile->GetDataSizeType() == DataSizeType::Accurate ||\n+         infile->GetDataSizeType() == DataSizeType::UpperBound);\n+\n+  File::DirectIOFile outfile(outfile_path, File::AccessMode::Write);\n+  if (!outfile.IsOpen())\n+  {\n+    PanicAlertFmtT(\n+        "Failed to open the output file \\"{0}\\".\\n"\n+        "Check that you have permissions to write the target folder and that the media can "\n+        "be written.",\n+        outfile_path);\n+    return false;\n+  }\n+\n+  const u64 disc_size = infile->GetDataSize();\n+\n+  // These match the values used by standard WBFS tools (wwt, WBFS Manager)\n+  static constexpr u8 hd_sector_shift = 9;\n+  static constexpr u8 wbfs_sector_shift = 21;\n+  static constexpr u64 hd_sector_size = 1ull << hd_sector_shift;\n+  static constexpr u64 wbfs_sector_size = 1ull << wbfs_sector_shift;\n+\n+  const u64 blocks_per_disc = (disc_size + wbfs_sector_size - 1) / wbfs_sector_size;\n+  const u64 disc_info_size =\n+      Common::AlignUp(WII_DISC_HEADER_SIZE + blocks_per_disc * sizeof(u16), hd_sector_size);\n+\n+  // Read disc header (first 256 bytes contain disc_id, disc_num, title, etc.)\n+  std::vector<u8> disc_header(WII_DISC_HEADER_SIZE, 0);\n+  if (!infile->Read(0, WII_DISC_HEADER_SIZE, disc_header.data()))\n+  {\n+    PanicAlertFmtT("Failed to read from the input file \\"{0}\\".", infile_path);\n+    return false;\n+  }\n+\n+  // Use Volume for partition info and decrypted reads\n+  struct PartitionInfo\n+  {\n+    u64 data_offset;\n+    u64 data_size;\n+    Partition partition;\n+  };\n+  std::vector<PartitionInfo> partitions;\n+\n+  std::unique_ptr<VolumeDisc> volume = CreateDisc(infile_path);\n+  if (volume)\n+  {\n+    for (const Partition& partition : volume->GetPartitions())\n+    {\n+      const std::optional<u64> data_offset =\n+          volume->ReadSwappedAndShifted(partition.offset + 0x2B8, PARTITION_NONE);\n+      const std::optional<u64> data_size =\n+          volume->ReadSwappedAndShifted(partition.offset + 0x2BC, PARTITION_NONE);\n+      if (!data_offset || !data_size)\n+        continue;\n+\n+      PartitionInfo info;\n+      info.data_offset = partition.offset + *data_offset;\n+      info.data_size = *data_size;\n+      info.partition = partition;\n+      partitions.push_back(info);\n+    }\n+  }\n+\n+  // NKit v2 gap type bitmap: 1 bit per block, MSB-first, always sized for dual-layer\n+  const u64 gap_type_blocks = (DL_DVD_SIZE + wbfs_sector_size - 1) / wbfs_sector_size;\n+  const u64 gap_type_bytes = (gap_type_blocks + 7) / 8;\n+  std::vector<u8> gap_type(gap_type_bytes, 0);\n+\n+  // Compute data_start up front so we can write sectors during the scan\n+  const u64 data_start = Common::AlignUp(hd_sector_size + disc_info_size, wbfs_sector_size);\n+  const u16 wlba_base = static_cast<u16>(data_start / wbfs_sector_size);\n+\n+  // Single pass: scan, classify, hash, and write used sectors in one loop\n+  std::vector<u8> sector_buf(wbfs_sector_size, 0);\n+  std::vector<u16> wlba_table(blocks_per_disc, 0);\n+  u16 used_count = 0;\n+\n+  // NKit v2 stores four hash digests for verification\n+  auto sha1_ctx = Common::SHA1::CreateContext();\n+  u32 crc = Common::StartCRC32();\n+  mbedtls_md5_context md5_ctx{};\n+  mbedtls_md5_init(&md5_ctx);\n+  mbedtls_md5_starts_ret(&md5_ctx);\n+  XXH64_state_t* xxh_state = XXH64_createState();\n+  XXH64_reset(xxh_state, 0);\n+\n+  for (u64 i = 0; i < blocks_per_disc; i++)\n+  {\n+    if (i % 100 == 0)\n+    {\n+      const bool was_cancelled =\n+          !callback(Common::GetStringT("Converting"),\n+                    static_cast<float>(i) / static_cast<float>(blocks_per_disc));\n+      if (was_cancelled)\n+      {\n+        XXH64_freeState(xxh_state);\n+        mbedtls_md5_free(&md5_ctx);\n+        outfile.Close();\n+        File::Delete(outfile_path);', 'path': 'Source/Core/DiscIO/WbfsBlob.cpp', 'position': 401, 'original_position': 401, 'commit_id': '24b41d58df2315831b74f76b95417f2739d02f9d', 'user': {'login': 'phire', 'id': 138484, 'node_id': 'MDQ6VXNlcjEzODQ4NA==', 'avatar_url': 'https://avatars.githubusercontent.com/u/138484?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/phire', 'html_url': 'https://github.com/phire', 'followers_url': 'https://api.github.com/users/phire/followers', 'following_url': 'https://api.github.com/users/phire/following{/other_user}', 'gists_url': 'https://api.github.com/users/phire/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/phire/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/phire/subscriptions', 'organizations_url': 'https://api.github.com/users/phire/orgs', 'repos_url': 'https://api.github.com/users/phire/repos', 'events_url': 'https://api.github.com/users/phire/events{/privacy}', 'received_events_url': 'https://api.github.com/users/phire/received_events', 'type': 'User', 'user_view_type': 'public', 'site_admin': False}, 'body': 'Use `Common::ScopeGuard` to avoid this manual cleanup. ', 'created_at': '2026-07-18T21:58:40Z', 'updated_at': '2026-07-18T22:26:23Z', 'html_url': 'https://github.com/dolphin-emu/dolphin/pull/14731#discussion_r3609268698', 'pull_request_url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/14731', 'author_association': 'MEMBER', '_links': {'self': {'href': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/comments/3609268698'}, 'html': {'href': 'https://github.com/dolphin-emu/dolphin/pull/14731#discussion_r3609268698'}, 'pull_request': {'href': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/14731'}}, 'original_commit_id': '24b41d58df2315831b74f76b95417f2739d02f9d', 'reactions': {'url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/comments/3609268698/reactions', 'total_count': 0, '+1': 0, '-1': 0, 'laugh': 0, 'hooray': 0, 'confused': 0, 'heart': 0, 'rocket': 0, 'eyes': 0}}, {'id': 3609277919, 'node_id': 'PRRC_kwDOALCn2M7XITXf', 'url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/comments/3609277919', 'pull_request_review_id': 4729322283, 'diff_hunk': '@@ -119,22 +144,191 @@ bool WbfsFileReader::ReadHeader()\n   return m_header.disc_table[0] != 0;\n }\n \n+bool WbfsFileReader::ReadNKitHeader()\n+{\n+  const u64 gap_type_blocks = (DL_DVD_SIZE + m_wbfs_sector_size - 1) / m_wbfs_sector_size;\n+  m_nkit_info = NKit::ReadHeaderFromFile(m_files[0].file, NKit::HEADER_OFFSET, gap_type_blocks);\n+  if (!m_nkit_info.valid)\n+    return false;\n+\n+  m_has_nkit_header = true;\n+  return true;\n+}\n+\n+bool WbfsFileReader::IsBlockStored(u64 block_index) const\n+{\n+  return block_index < m_blocks_per_disc && m_wlba_table[block_index] != 0;\n+}\n+\n+bool WbfsFileReader::IsGapJunk(u64 block_index) const\n+{\n+  return NKit::IsGapJunk(m_nkit_info.gap_type, block_index);\n+}\n+\n+void WbfsFileReader::GenerateJunkData(u64 disc_offset, u64 size, u8* out) const\n+{\n+  LaggedFibonacciGenerator::FillJunkData(out, static_cast<size_t>(size), disc_offset, m_disc_id,\n+                                         m_disc_num);\n+}\n+\n+void WbfsFileReader::ReadPartitionInfo()\n+{\n+  std::unique_ptr<VolumeDisc> volume = CreateDisc(CopyReader());\n+  if (!volume)\n+    return;\n+\n+  for (const Partition& partition : volume->GetPartitions())\n+  {\n+    const auto& ticket = volume->GetTicket(partition);\n+    const std::array<u8, 16> title_key = ticket.GetTitleKey();\n+\n+    u8 data_info[8];\n+    if (!Read(partition.offset + 0x2B8, 8, data_info))\n+      continue;\n+\n+    PartitionEntry entry;\n+    entry.data_offset = partition.offset + (static_cast<u64>(Common::swap32(data_info)) << 2);\n+    entry.data_size = static_cast<u64>(Common::swap32(data_info + 4)) << 2;\n+    entry.key = title_key;\n+    m_partitions.push_back(entry);\n+  }\n+}\n+\n+const WbfsFileReader::PartitionEntry* WbfsFileReader::FindPartition(u64 disc_offset) const\n+{\n+  for (const auto& p : m_partitions)\n+  {\n+    if (disc_offset >= p.data_offset && disc_offset < p.data_offset + p.data_size)\n+      return &p;\n+  }\n+  return nullptr;\n+}\n+\n+const WbfsFileReader::PartitionEntry*\n+WbfsFileReader::FindPartitionByDataOffset(u64 partition_data_offset) const\n+{\n+  for (const auto& p : m_partitions)\n+  {\n+    if (p.data_offset == partition_data_offset)\n+      return &p;\n+  }\n+  return nullptr;\n+}\n+\n+bool WbfsFileReader::SupportsReadWiiDecrypted(u64 offset, u64 size, u64 partition_data_offset) const\n+{\n+  if (!m_has_nkit_header)\n+    return false;\n+\n+  const u64 block_in_partition = offset / VolumeWii::BLOCK_DATA_SIZE;\n+  const u64 disc_offset = partition_data_offset + block_in_partition * VolumeWii::BLOCK_TOTAL_SIZE;\n+  const u64 wbfs_block = disc_offset >> m_header.wbfs_sector_shift;\n+\n+  return wbfs_block < m_blocks_per_disc && !IsBlockStored(wbfs_block);\n+}\n+\n+bool WbfsFileReader::ReadWiiDecrypted(u64 offset, u64 size, u8* out_ptr, u64 partition_data_offset)\n+{\n+  const PartitionEntry* pe = FindPartitionByDataOffset(partition_data_offset);\n+  if (!pe)\n+    return false;\n+\n+  auto aes_ctx = Common::AES::CreateContextDecrypt(pe->key.data());\n+  std::vector<u8> encrypted(VolumeWii::BLOCK_TOTAL_SIZE);\n+  std::vector<u8> decrypted(VolumeWii::BLOCK_DATA_SIZE);\n+\n+  while (size > 0)\n+  {\n+    const u64 block_in_partition = offset / VolumeWii::BLOCK_DATA_SIZE;\n+    const u64 offset_in_block = offset % VolumeWii::BLOCK_DATA_SIZE;\n+    const u64 bytes_in_block = VolumeWii::BLOCK_DATA_SIZE - offset_in_block;\n+    const size_t read_size = static_cast<size_t>(std::min(bytes_in_block, size));\n+\n+    const u64 disc_offset =\n+        partition_data_offset + block_in_partition * VolumeWii::BLOCK_TOTAL_SIZE;\n+    const u64 wbfs_block = disc_offset >> m_header.wbfs_sector_shift;\n+\n+    if (IsBlockStored(wbfs_block))\n+    {\n+      u64 available;\n+      auto& file = SeekToCluster(disc_offset, &available);\n+      if (available < VolumeWii::BLOCK_TOTAL_SIZE ||\n+          !file.Read(encrypted.data(), VolumeWii::BLOCK_TOTAL_SIZE))\n+        return false;\n+      VolumeWii::DecryptBlockData(encrypted.data(), decrypted.data(), aes_ctx.get());\n+      std::memcpy(out_ptr, decrypted.data() + offset_in_block, read_size);\n+    }', 'path': 'Source/Core/DiscIO/WbfsBlob.cpp', 'position': 204, 'original_position': 204, 'commit_id': '24b41d58df2315831b74f76b95417f2739d02f9d', 'user': {'login': 'phire', 'id': 138484, 'node_id': 'MDQ6VXNlcjEzODQ4NA==', 'avatar_url': 'https://avatars.githubusercontent.com/u/138484?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/phire', 'html_url': 'https://github.com/phire', 'followers_url': 'https://api.github.com/users/phire/followers', 'following_url': 'https://api.github.com/users/phire/following{/other_user}', 'gists_url': 'https://api.github.com/users/phire/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/phire/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/phire/subscriptions', 'organizations_url': 'https://api.github.com/users/phire/orgs', 'repos_url': 'https://api.github.com/users/phire/repos', 'events_url': 'https://api.github.com/users/phire/events{/privacy}', 'received_events_url': 'https://api.github.com/users/phire/received_events', 'type': 'User', 'user_view_type': 'public', 'site_admin': False}, 'body': "> ReadWiiDecrypted still contains manual AES decryption for stored blocks because VolumeWii::EncryptGroup calls it directly without checking SupportsReadWiiDecrypted\n\nBut you are calling `EncryptGroup` for blocks that don't have data, right? I don't see why this would be reachable.", 'created_at': '2026-07-18T22:05:05Z', 'updated_at': '2026-07-18T22:26:23Z', 'html_url': 'https://github.com/dolphin-emu/dolphin/pull/14731#discussion_r3609277919', 'pull_request_url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/14731', 'author_association': 'MEMBER', '_links': {'self': {'href': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/comments/3609277919'}, 'html': {'href': 'https://github.com/dolphin-emu/dolphin/pull/14731#discussion_r3609277919'}, 'pull_request': {'href': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/14731'}}, 'original_commit_id': '24b41d58df2315831b74f76b95417f2739d02f9d', 'reactions': {'url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/comments/3609277919/reactions', 'total_count': 0, '+1': 0, '-1': 0, 'laugh': 0, 'hooray': 0, 'confused': 0, 'heart': 0, 'rocket': 0, 'eyes': 0}}, {'id': 3609296950, 'node_id': 'PRRC_kwDOALCn2M7XIYA2', 'url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/comments/3609296950', 'pull_request_review_id': 4729322283, 'diff_hunk': '@@ -186,7 +380,304 @@ std::unique_ptr<WbfsFileReader> WbfsFileReader::Create(File::DirectIOFile file,\n   if (!reader->IsGood())\n     reader.reset();\n \n+  if (reader && reader->m_has_nkit_header)\n+    reader->ReadPartitionInfo();\n+\n   return reader;\n }\n \n+// Converts any disc image to WBFS with an NKit v2 header for lossless round-trips.\n+// Strips disc-level junk and partition-level junk (encrypted sectors whose decrypted\n+// content is zero or LFG padding), records a junk bitmap for reconstruction.\n+// See: https://github.com/dolphin-emu/dolphin/pull/14731\n+bool ConvertToWBFS(BlobReader* infile, const std::string& infile_path,\n+                   const std::string& outfile_path, const CompressCB& callback)\n+{\n+  ASSERT(infile->GetDataSizeType() == DataSizeType::Accurate ||\n+         infile->GetDataSizeType() == DataSizeType::UpperBound);\n+\n+  File::DirectIOFile outfile(outfile_path, File::AccessMode::Write);\n+  if (!outfile.IsOpen())\n+  {\n+    PanicAlertFmtT(\n+        "Failed to open the output file \\"{0}\\".\\n"\n+        "Check that you have permissions to write the target folder and that the media can "\n+        "be written.",\n+        outfile_path);\n+    return false;\n+  }\n+\n+  const u64 disc_size = infile->GetDataSize();\n+\n+  // These match the values used by standard WBFS tools (wwt, WBFS Manager)\n+  static constexpr u8 hd_sector_shift = 9;\n+  static constexpr u8 wbfs_sector_shift = 21;\n+  static constexpr u64 hd_sector_size = 1ull << hd_sector_shift;\n+  static constexpr u64 wbfs_sector_size = 1ull << wbfs_sector_shift;\n+\n+  const u64 blocks_per_disc = (disc_size + wbfs_sector_size - 1) / wbfs_sector_size;\n+  const u64 disc_info_size =\n+      Common::AlignUp(WII_DISC_HEADER_SIZE + blocks_per_disc * sizeof(u16), hd_sector_size);\n+\n+  // Read disc header (first 256 bytes contain disc_id, disc_num, title, etc.)\n+  std::vector<u8> disc_header(WII_DISC_HEADER_SIZE, 0);\n+  if (!infile->Read(0, WII_DISC_HEADER_SIZE, disc_header.data()))\n+  {\n+    PanicAlertFmtT("Failed to read from the input file \\"{0}\\".", infile_path);\n+    return false;\n+  }\n+\n+  // Use Volume for partition info and decrypted reads\n+  struct PartitionInfo\n+  {\n+    u64 data_offset;\n+    u64 data_size;\n+    Partition partition;\n+  };\n+  std::vector<PartitionInfo> partitions;\n+\n+  std::unique_ptr<VolumeDisc> volume = CreateDisc(infile_path);\n+  if (volume)\n+  {\n+    for (const Partition& partition : volume->GetPartitions())\n+    {\n+      const std::optional<u64> data_offset =\n+          volume->ReadSwappedAndShifted(partition.offset + 0x2B8, PARTITION_NONE);\n+      const std::optional<u64> data_size =\n+          volume->ReadSwappedAndShifted(partition.offset + 0x2BC, PARTITION_NONE);\n+      if (!data_offset || !data_size)\n+        continue;\n+\n+      PartitionInfo info;\n+      info.data_offset = partition.offset + *data_offset;\n+      info.data_size = *data_size;\n+      info.partition = partition;\n+      partitions.push_back(info);\n+    }\n+  }\n+\n+  // NKit v2 gap type bitmap: 1 bit per block, MSB-first, always sized for dual-layer\n+  const u64 gap_type_blocks = (DL_DVD_SIZE + wbfs_sector_size - 1) / wbfs_sector_size;\n+  const u64 gap_type_bytes = (gap_type_blocks + 7) / 8;\n+  std::vector<u8> gap_type(gap_type_bytes, 0);\n+\n+  // Compute data_start up front so we can write sectors during the scan\n+  const u64 data_start = Common::AlignUp(hd_sector_size + disc_info_size, wbfs_sector_size);\n+  const u16 wlba_base = static_cast<u16>(data_start / wbfs_sector_size);\n+\n+  // Single pass: scan, classify, hash, and write used sectors in one loop\n+  std::vector<u8> sector_buf(wbfs_sector_size, 0);\n+  std::vector<u16> wlba_table(blocks_per_disc, 0);\n+  u16 used_count = 0;\n+\n+  // NKit v2 stores four hash digests for verification\n+  auto sha1_ctx = Common::SHA1::CreateContext();\n+  u32 crc = Common::StartCRC32();\n+  mbedtls_md5_context md5_ctx{};\n+  mbedtls_md5_init(&md5_ctx);\n+  mbedtls_md5_starts_ret(&md5_ctx);\n+  XXH64_state_t* xxh_state = XXH64_createState();\n+  XXH64_reset(xxh_state, 0);\n+\n+  for (u64 i = 0; i < blocks_per_disc; i++)\n+  {\n+    if (i % 100 == 0)\n+    {\n+      const bool was_cancelled =\n+          !callback(Common::GetStringT("Converting"),\n+                    static_cast<float>(i) / static_cast<float>(blocks_per_disc));\n+      if (was_cancelled)\n+      {\n+        XXH64_freeState(xxh_state);\n+        mbedtls_md5_free(&md5_ctx);\n+        outfile.Close();\n+        File::Delete(outfile_path);\n+        return false;\n+      }\n+    }\n+\n+    const u64 offset = i * wbfs_sector_size;\n+    const size_t sz = static_cast<size_t>(std::min(wbfs_sector_size, disc_size - offset));\n+\n+    if (!infile->Read(offset, sz, sector_buf.data()))\n+    {\n+      PanicAlertFmtT("Failed to read from the input file \\"{0}\\".", infile_path);\n+      XXH64_freeState(xxh_state);\n+      mbedtls_md5_free(&md5_ctx);\n+      outfile.Close();\n+      File::Delete(outfile_path);\n+      return false;\n+    }\n+\n+    // Update all four hashes with the full disc data\n+    sha1_ctx->Update(sector_buf.data(), sz);\n+    crc = Common::UpdateCRC32(crc, sector_buf.data(), sz);\n+    mbedtls_md5_update_ret(&md5_ctx, sector_buf.data(), sz);\n+    XXH64_update(xxh_state, sector_buf.data(), sz);\n+\n+    // Find which partition (if any) this block belongs to\n+    const u32 start_sector = static_cast<u32>(offset / VolumeWii::BLOCK_TOTAL_SIZE);\n+    const u32 end_sector = static_cast<u32>((offset + sz) / VolumeWii::BLOCK_TOTAL_SIZE);\n+    const auto it = std::ranges::find_if(partitions, [&](const PartitionInfo& p) {\n+      const u32 p_start = static_cast<u32>(p.data_offset / VolumeWii::BLOCK_TOTAL_SIZE);\n+      const u32 p_end =\n+          static_cast<u32>((p.data_offset + p.data_size) / VolumeWii::BLOCK_TOTAL_SIZE);\n+      return start_sector >= p_start && end_sector <= p_end;\n+    });\n+    const PartitionInfo* pi = (it != partitions.end()) ? &*it : nullptr;\n+\n+    bool is_used = true;\n+\n+    if (pi)\n+    {\n+      // Partition data: use Volume::Read to get decrypted data for junk/zero checks.\n+      // All-zero and all-junk are checked separately - mixed blocks are stored.\n+      bool all_zero = true;\n+      bool all_junk = true;\n+      for (u64 sub = 0; sub < sz; sub += VolumeWii::BLOCK_TOTAL_SIZE)\n+      {\n+        const u64 abs = offset + sub;\n+        const u64 sector_in_partition = (abs - pi->data_offset) / VolumeWii::BLOCK_TOTAL_SIZE;\n+        const u64 partition_offset = sector_in_partition * VolumeWii::BLOCK_DATA_SIZE;\n+\n+        u8 decrypted[VolumeWii::BLOCK_DATA_SIZE];\n+        if (!volume->Read(partition_offset, VolumeWii::BLOCK_DATA_SIZE, decrypted, pi->partition))\n+          break;\n+\n+        const bool sector_zero = std::ranges::all_of(decrypted, [](u8 b) { return b == 0; });\n+        if (!sector_zero)\n+        {\n+          all_zero = false;\n+          const bool sector_junk = LaggedFibonacciGenerator::IsJunkBlock(\n+              decrypted, VolumeWii::BLOCK_DATA_SIZE, partition_offset, disc_header.data(),\n+              disc_header[6]);\n+          if (!sector_junk)\n+            all_junk = false;\n+        }\n+\n+        if (!all_zero && !all_junk)\n+          break;\n+      }\n+\n+      if (all_zero || all_junk)\n+      {\n+        if (all_junk && !all_zero)\n+          gap_type[i / 8] |= static_cast<u8>(1 << (7 - (i & 7)));\n+        is_used = false;\n+      }\n+    }\n+    else\n+    {\n+      // Non-partition data: check disc-level zero and junk patterns\n+      const bool is_zero = std::ranges::all_of(sector_buf, [](u8 b) { return b == 0; });\n+      if (is_zero)\n+      {\n+        is_used = false;\n+      }\n+      else if (LaggedFibonacciGenerator::IsJunkBlock(sector_buf.data(), sz, offset,\n+                                                     disc_header.data(), disc_header[6]))\n+      {\n+        gap_type[i / 8] |= static_cast<u8>(1 << (7 - (i & 7)));\n+        is_used = false;\n+      }\n+    }\n+\n+    if (is_used)\n+    {\n+      // Write sector directly to output\n+      const u64 out_offset = data_start + static_cast<u64>(used_count) * wbfs_sector_size;\n+      outfile.Seek(out_offset, File::SeekOrigin::Begin);\n+      std::fill(sector_buf.begin() + sz, sector_buf.end(), u8{0});\n+      if (!outfile.Write(sector_buf.data(), wbfs_sector_size))\n+      {\n+        PanicAlertFmtT("Failed to write the output file \\"{0}\\".\\n"\n+                       "Check that you have enough space available on the target drive.",\n+                       outfile_path);\n+        XXH64_freeState(xxh_state);\n+        mbedtls_md5_free(&md5_ctx);\n+        outfile.Close();\n+        File::Delete(outfile_path);\n+        return false;\n+      }\n+\n+      wlba_table[i] = Common::swap16(static_cast<u16>(wlba_base + used_count));\n+      used_count++;\n+    }\n+  }\n+\n+  // Finalize hashes\n+  const Common::SHA1::Digest sha1_digest = sha1_ctx->Finish();\n+  const u64 xxh_digest = XXH64_digest(xxh_state);\n+  XXH64_freeState(xxh_state);\n+\n+  // Write WBFS header (seek back to start)\n+  const u64 total_size = data_start + static_cast<u64>(used_count) * wbfs_sector_size;\n+  const u32 hd_sector_count = static_cast<u32>(total_size / hd_sector_size);\n+\n+  WbfsHeader header{};\n+  header.magic = WBFS_MAGIC;\n+  header.hd_sector_count = Common::swap32(hd_sector_count);\n+  header.hd_sector_shift = hd_sector_shift;\n+  header.wbfs_sector_shift = wbfs_sector_shift;\n+  header.disc_table[0] = 1;\n+\n+  outfile.Seek(0, File::SeekOrigin::Begin);\n+  if (!outfile.Write(Common::AsU8Span(header)))\n+  {\n+    PanicAlertFmtT("Failed to write the output file \\"{0}\\".\\n"\n+                   "Check that you have enough space available on the target drive.",\n+                   outfile_path);\n+    outfile.Close();\n+    File::Delete(outfile_path);\n+    return false;\n+  }', 'path': 'Source/Core/DiscIO/WbfsBlob.cpp', 'position': 540, 'original_position': 540, 'commit_id': '24b41d58df2315831b74f76b95417f2739d02f9d', 'user': {'login': 'phire', 'id': 138484, 'node_id': 'MDQ6VXNlcjEzODQ4NA==', 'avatar_url': 'https://avatars.githubusercontent.com/u/138484?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/phire', 'html_url': 'https://github.com/phire', 'followers_url': 'https://api.github.com/users/phire/followers', 'following_url': 'https://api.github.com/users/phire/following{/other_user}', 'gists_url': 'https://api.github.com/users/phire/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/phire/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/phire/subscriptions', 'organizations_url': 'https://api.github.com/users/phire/orgs', 'repos_url': 'https://api.github.com/users/phire/repos', 'events_url': 'https://api.github.com/users/phire/events{/privacy}', 'received_events_url': 'https://api.github.com/users/phire/received_events', 'type': 'User', 'user_view_type': 'public', 'site_admin': False}, 'body': 'I think this is the job for a lambda.\n\nPut this near the top of the function:\n\n```c++\nauto write_failed_panic [&] {\n  PanicAlertFmtT("Failed to write..... \n  return false;\n};\n```\n\nWhen combined with `Common::ScopeGuard` to handle closing/deleting (as discussed above), you should be able to simplify all these down to:\n\n```c++\nif (!outfile.Write(Common::AsU8Span(header)))\n{\n  return write_failed_panic();\n}\n```', 'created_at': '2026-07-18T22:18:18Z', 'updated_at': '2026-07-18T22:26:23Z', 'html_url': 'https://github.com/dolphin-emu/dolphin/pull/14731#discussion_r3609296950', 'pull_request_url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/14731', 'author_association': 'MEMBER', '_links': {'self': {'href': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/comments/3609296950'}, 'html': {'href': 'https://github.com/dolphin-emu/dolphin/pull/14731#discussion_r3609296950'}, 'pull_request': {'href': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/14731'}}, 'original_commit_id': '24b41d58df2315831b74f76b95417f2739d02f9d', 'reactions': {'url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/comments/3609296950/reactions', 'total_count': 0, '+1': 0, '-1': 0, 'laugh': 0, 'hooray': 0, 'confused': 0, 'heart': 0, 'rocket': 0, 'eyes': 0}}], 'type': 'gh_pull_request_review'}
2026-07-18T20:47:17.769776	{'source': 'ghhookparser', 'repo': 'dolphin-emu/dolphin', 'author': 'thethiny', 'action': 'submitted', 'pr_id': 14731, 'pr_title': 'Convert To WBFS Support', 'state': 'commented', 'url': 'https://github.com/dolphin-emu/dolphin/pull/14731#pullrequestreview-4729277002', 'comments': [{'id': 3609166128, 'node_id': 'PRRC_kwDOALCn2M7XH4Ew', 'url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/comments/3609166128', 'pull_request_review_id': 4729277002, 'diff_hunk': '@@ -119,22 +144,241 @@ bool WbfsFileReader::ReadHeader()\n   return m_header.disc_table[0] != 0;\n }\n \n+bool WbfsFileReader::ReadNKitHeader()\n+{\n+  // NKit v2 header at offset 0x10000 in the WBFS file\n+  // Reference: https://github.com/encounter/nod/blob/d10d376/nod/src/io/nkit.rs\n+  static constexpr u64 NKIT_OFFSET = 0x10000;\n+\n+  u8 version[8];\n+  m_files[0].file.Seek(NKIT_OFFSET, File::SeekOrigin::Begin);\n+  if (!m_files[0].file.Read(version, sizeof(version)))\n+    return false;\n+  if (std::memcmp(version, "NKIT  v2", 8) != 0)\n+    return false;\n+\n+  u8 header_meta[4];\n+  if (!m_files[0].file.Read(header_meta, sizeof(header_meta)))\n+    return false;\n+\n+  const u16 header_size =\n+      (static_cast<u16>(header_meta[0]) << 8) | header_meta[1];\n+  const u16 flags =\n+      (static_cast<u16>(header_meta[2]) << 8) | header_meta[3];\n+\n+  if (header_size < 12)\n+    return false;\n+\n+  const size_t remaining = header_size - 12;\n+  std::vector<u8> header_data(remaining);\n+  if (!m_files[0].file.Read(header_data.data(), remaining))\n+    return false;\n+\n+  size_t pos = 0;\n+  if (flags & 0x01)  // Size\n+  {\n+    if (pos + 8 > remaining)\n+      return false;\n+    m_nkit_disc_size = 0;\n+    for (int b = 0; b < 8; b++)\n+      m_nkit_disc_size = (m_nkit_disc_size << 8) | header_data[pos + b];\n+    pos += 8;\n+  }\n+  if (flags & 0x02)  // CRC32\n+    pos += 4;\n+  if (flags & 0x04)  // MD5\n+    pos += 16;\n+  if (flags & 0x08)  // SHA-1\n+    pos += 20;\n+  if (flags & 0x10)  // XXHash64\n+    pos += 8;\n+  if (flags & 0x20)  // Key\n+  {\n+    if (pos + 2 > remaining)\n+      return false;\n+    const u16 key_len =\n+        (static_cast<u16>(header_data[pos]) << 8) | header_data[pos + 1];\n+    pos += 2 + key_len;\n+  }\n+\n+  // Junk bitmap is always sized for dual-layer (covers both SL and DL discs)\n+  const u64 junk_bits_blocks =\n+      (DL_DVD_SIZE + m_wbfs_sector_size - 1) / m_wbfs_sector_size;\n+  const u64 junk_bits_bytes = (junk_bits_blocks + 7) / 8;\n+  m_junk_bits.resize(static_cast<size_t>(junk_bits_bytes));\n+  if (!m_files[0].file.Read(m_junk_bits.data(), static_cast<size_t>(junk_bits_bytes)))\n+    return false;\n+\n+  m_has_nkit_header = true;\n+  return true;\n+}\n+\n+bool WbfsFileReader::IsNKitJunkBlock(u64 block_index) const\n+{\n+  const size_t byte_index = static_cast<size_t>(block_index / 8);\n+  if (byte_index >= m_junk_bits.size())\n+    return false;\n+  return (m_junk_bits[byte_index] & (1 << (7 - (block_index & 7)))) != 0;\n+}\n+\n+void WbfsFileReader::GenerateJunkData(u64 disc_offset, u64 size, u8* out) const\n+{\n+  LaggedFibonacciGenerator::FillJunkData(out, static_cast<size_t>(size), disc_offset,\n+                                          m_disc_id, m_disc_num);\n+}\n+\n+void WbfsFileReader::ReadPartitionInfo()\n+{\n+  std::unique_ptr<VolumeDisc> volume = CreateDisc(CopyReader());\n+  if (!volume)\n+    return;\n+\n+  for (const Partition& partition : volume->GetPartitions())\n+  {\n+    const auto& ticket = volume->GetTicket(partition);\n+    const std::array<u8, 16> title_key = ticket.GetTitleKey();\n+\n+    u8 data_info[8];\n+    if (!Read(partition.offset + 0x2B8, 8, data_info))\n+      continue;\n+\n+    PartitionEntry entry;\n+    entry.data_offset = partition.offset + (static_cast<u64>(Common::swap32(data_info)) << 2);\n+    entry.data_size = static_cast<u64>(Common::swap32(data_info + 4)) << 2;\n+    entry.key = title_key;\n+    m_partitions.push_back(entry);\n+  }\n+}\n+\n+const WbfsFileReader::PartitionEntry* WbfsFileReader::FindPartition(u64 disc_offset) const\n+{\n+  for (const auto& p : m_partitions)\n+  {\n+    if (disc_offset >= p.data_offset && disc_offset < p.data_offset + p.data_size)\n+      return &p;\n+  }\n+  return nullptr;\n+}\n+\n+const WbfsFileReader::PartitionEntry*\n+WbfsFileReader::FindPartitionByDataOffset(u64 partition_data_offset) const\n+{\n+  for (const auto& p : m_partitions)\n+  {\n+    if (p.data_offset == partition_data_offset)\n+      return &p;\n+  }\n+  return nullptr;\n+}\n+\n+bool WbfsFileReader::SupportsReadWiiDecrypted(u64 offset, u64 size,\n+                                               u64 partition_data_offset) const\n+{\n+  return m_has_nkit_header && FindPartitionByDataOffset(partition_data_offset) != nullptr;\n+}\n+\n+bool WbfsFileReader::ReadWiiDecrypted(u64 offset, u64 size, u8* out_ptr,\n+                                       u64 partition_data_offset)\n+{\n+  const PartitionEntry* pe = FindPartitionByDataOffset(partition_data_offset);\n+  if (!pe)\n+    return false;\n+\n+  while (size > 0)\n+  {\n+    const u64 block_in_partition = offset / VolumeWii::BLOCK_DATA_SIZE;\n+    const u64 offset_in_block = offset % VolumeWii::BLOCK_DATA_SIZE;\n+    const u64 bytes_in_block = VolumeWii::BLOCK_DATA_SIZE - offset_in_block;\n+    const u64 read_size = std::min(bytes_in_block, size);\n+\n+    const u64 disc_offset =\n+        partition_data_offset + block_in_partition * VolumeWii::BLOCK_TOTAL_SIZE;\n+    const u64 wbfs_block = disc_offset >> m_header.wbfs_sector_shift;\n+\n+    if (wbfs_block < m_blocks_per_disc && m_wlba_table[wbfs_block] != 0)\n+    {\n+      // Stored sector: read encrypted data and decrypt\n+      u8 encrypted[VolumeWii::BLOCK_TOTAL_SIZE];\n+      u64 available;\n+      auto& file = SeekToCluster(disc_offset, &available);\n+      if (available < VolumeWii::BLOCK_TOTAL_SIZE || !file.Read(encrypted, VolumeWii::BLOCK_TOTAL_SIZE))\n+        return false;\n+      auto aes_ctx = Common::AES::CreateContextDecrypt(pe->key.data());\n+      u8 decrypted[VolumeWii::BLOCK_DATA_SIZE];\n+      VolumeWii::DecryptBlockData(encrypted, decrypted, aes_ctx.get());\n+      std::memcpy(out_ptr, decrypted + offset_in_block, static_cast<size_t>(read_size));', 'path': 'Source/Core/DiscIO/WbfsBlob.cpp', 'position': 1, 'original_position': 234, 'commit_id': '81f336974c3eb2f93c05073734d2d7dc16309a6a', 'user': {'login': 'thethiny', 'id': 6018214, 'node_id': 'MDQ6VXNlcjYwMTgyMTQ=', 'avatar_url': 'https://avatars.githubusercontent.com/u/6018214?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/thethiny', 'html_url': 'https://github.com/thethiny', 'followers_url': 'https://api.github.com/users/thethiny/followers', 'following_url': 'https://api.github.com/users/thethiny/following{/other_user}', 'gists_url': 'https://api.github.com/users/thethiny/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/thethiny/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/thethiny/subscriptions', 'organizations_url': 'https://api.github.com/users/thethiny/orgs', 'repos_url': 'https://api.github.com/users/thethiny/repos', 'events_url': 'https://api.github.com/users/thethiny/events{/privacy}', 'received_events_url': 'https://api.github.com/users/thethiny/received_events', 'type': 'User', 'user_view_type': 'public', 'site_admin': False}, 'body': 'Implemented so `SupportsReadWiiDecrypted` returns true only when the block is non-stored (`wlba == 0`). For stored blocks it returns `false` and `VolumeWii` handles decryption via `Read()`.', 'created_at': '2026-07-18T20:47:15Z', 'updated_at': '2026-07-18T20:47:16Z', 'html_url': 'https://github.com/dolphin-emu/dolphin/pull/14731#discussion_r3609166128', 'pull_request_url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/14731', 'author_association': 'NONE', '_links': {'self': {'href': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/comments/3609166128'}, 'html': {'href': 'https://github.com/dolphin-emu/dolphin/pull/14731#discussion_r3609166128'}, 'pull_request': {'href': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/14731'}}, 'original_commit_id': '81f336974c3eb2f93c05073734d2d7dc16309a6a', 'reactions': {'url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/comments/3609166128/reactions', 'total_count': 0, '+1': 0, '-1': 0, 'laugh': 0, 'hooray': 0, 'confused': 0, 'heart': 0, 'rocket': 0, 'eyes': 0}, 'in_reply_to_id': 3607361519}], 'type': 'gh_pull_request_review'}
2026-07-18T20:45:50.500440	{'source': 'ghhookparser', 'repo': 'dolphin-emu/dolphin', 'author': 'thethiny', 'action': 'submitted', 'pr_id': 14731, 'pr_title': 'Convert To WBFS Support', 'state': 'commented', 'url': 'https://github.com/dolphin-emu/dolphin/pull/14731#pullrequestreview-4729274722', 'comments': [{'id': 3609163923, 'node_id': 'PRRC_kwDOALCn2M7XH3iT', 'url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/comments/3609163923', 'pull_request_review_id': 4729274722, 'diff_hunk': '@@ -186,7 +430,362 @@ std::unique_ptr<WbfsFileReader> WbfsFileReader::Create(File::DirectIOFile file,\n   if (!reader->IsGood())\n     reader.reset();\n \n+  if (reader && reader->m_has_nkit_header)\n+    reader->ReadPartitionInfo();\n+\n   return reader;\n }\n \n+// Converts any disc image to WBFS with an NKit v2 header for lossless round-trips.\n+// Strips disc-level junk and partition-level junk (encrypted sectors whose decrypted\n+// content is zero or LFG padding), records a junk bitmap for reconstruction.\n+// See: https://github.com/dolphin-emu/dolphin/pull/14731\n+bool ConvertToWBFS(BlobReader* infile, const std::string& infile_path,\n+                   const std::string& outfile_path, const CompressCB& callback)\n+{\n+  ASSERT(infile->GetDataSizeType() == DataSizeType::Accurate);\n+\n+  File::DirectIOFile outfile(outfile_path, File::AccessMode::Write);\n+  if (!outfile.IsOpen())\n+  {\n+    PanicAlertFmtT(\n+        "Failed to open the output file \\"{0}\\".\\n"\n+        "Check that you have permissions to write the target folder and that the media can "\n+        "be written.",\n+        outfile_path);\n+    return false;\n+  }\n+\n+  const u64 disc_size = infile->GetDataSize();\n+\n+  // These match the values used by standard WBFS tools (wwt, WBFS Manager)\n+  static constexpr u8 hd_sector_shift = 9;\n+  static constexpr u8 wbfs_sector_shift = 21;\n+  static constexpr u64 hd_sector_size = 1ull << hd_sector_shift;\n+  static constexpr u64 wbfs_sector_size = 1ull << wbfs_sector_shift;\n+\n+  const u64 blocks_per_disc = (disc_size + wbfs_sector_size - 1) / wbfs_sector_size;\n+  const u64 disc_info_size =\n+      Common::AlignUp(WII_DISC_HEADER_SIZE + blocks_per_disc * sizeof(u16), hd_sector_size);\n+\n+  // Read disc header (first 256 bytes contain disc_id, disc_num, title, etc.)\n+  std::vector<u8> disc_header(WII_DISC_HEADER_SIZE, 0);\n+  if (!infile->Read(0, WII_DISC_HEADER_SIZE, disc_header.data()))\n+  {\n+    PanicAlertFmtT("Failed to read from the input file \\"{0}\\".", infile_path);\n+    return false;\n+  }\n+\n+  // Use Volume for partition info and decryption (per PR#14731 review)\n+  struct PartitionInfo\n+  {\n+    u64 data_offset;\n+    u64 data_size;\n+    std::unique_ptr<Common::AES::Context> aes_ctx;\n+  };\n+  std::vector<PartitionInfo> partitions;\n+\n+  std::unique_ptr<VolumeDisc> volume = CreateDisc(infile_path);\n+  if (volume)\n+  {\n+    for (const Partition& partition : volume->GetPartitions())\n+    {\n+      const auto& ticket = volume->GetTicket(partition);\n+      const std::array<u8, 16> title_key = ticket.GetTitleKey();\n+\n+      u8 data_info[8];\n+      if (!infile->Read(partition.offset + 0x2B8, 8, data_info))\n+        continue;\n+\n+      PartitionInfo info;\n+      info.data_offset = partition.offset + (static_cast<u64>(Common::swap32(data_info)) << 2);\n+      info.data_size = static_cast<u64>(Common::swap32(data_info + 4)) << 2;\n+      info.aes_ctx = Common::AES::CreateContextDecrypt(title_key.data());\n+      partitions.push_back(std::move(info));\n+    }\n+  }', 'path': 'Source/Core/DiscIO/WbfsBlob.cpp', 'position': 364, 'original_position': 394, 'commit_id': '24b41d58df2315831b74f76b95417f2739d02f9d', 'user': {'login': 'thethiny', 'id': 6018214, 'node_id': 'MDQ6VXNlcjYwMTgyMTQ=', 'avatar_url': 'https://avatars.githubusercontent.com/u/6018214?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/thethiny', 'html_url': 'https://github.com/thethiny', 'followers_url': 'https://api.github.com/users/thethiny/followers', 'following_url': 'https://api.github.com/users/thethiny/following{/other_user}', 'gists_url': 'https://api.github.com/users/thethiny/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/thethiny/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/thethiny/subscriptions', 'organizations_url': 'https://api.github.com/users/thethiny/orgs', 'repos_url': 'https://api.github.com/users/thethiny/repos', 'events_url': 'https://api.github.com/users/thethiny/events{/privacy}', 'received_events_url': 'https://api.github.com/users/thethiny/received_events', 'type': 'User', 'user_view_type': 'public', 'site_admin': False}, 'body': 'went with `Volume::Read` for the partition checks instead', 'created_at': '2026-07-18T20:45:48Z', 'updated_at': '2026-07-18T20:45:48Z', 'html_url': 'https://github.com/dolphin-emu/dolphin/pull/14731#discussion_r3609163923', 'pull_request_url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/14731', 'author_association': 'NONE', '_links': {'self': {'href': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/comments/3609163923'}, 'html': {'href': 'https://github.com/dolphin-emu/dolphin/pull/14731#discussion_r3609163923'}, 'pull_request': {'href': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/14731'}}, 'original_commit_id': '81f336974c3eb2f93c05073734d2d7dc16309a6a', 'reactions': {'url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/comments/3609163923/reactions', 'total_count': 0, '+1': 0, '-1': 0, 'laugh': 0, 'hooray': 0, 'confused': 0, 'heart': 0, 'rocket': 0, 'eyes': 0}, 'in_reply_to_id': 3607092935}], 'type': 'gh_pull_request_review'}
2026-07-18T20:44:52.062159	{'source': 'ghhookparser', 'repo': 'dolphin-emu/dolphin', 'author': 'thethiny', 'action': 'submitted', 'pr_id': 14731, 'pr_title': 'Convert To WBFS Support', 'state': 'commented', 'url': 'https://github.com/dolphin-emu/dolphin/pull/14731#pullrequestreview-4729273008', 'comments': [{'id': 3609162555, 'node_id': 'PRRC_kwDOALCn2M7XH3M7', 'url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/comments/3609162555', 'pull_request_review_id': 4729273008, 'diff_hunk': '@@ -119,22 +144,241 @@ bool WbfsFileReader::ReadHeader()\n   return m_header.disc_table[0] != 0;\n }\n \n+bool WbfsFileReader::ReadNKitHeader()\n+{\n+  // NKit v2 header at offset 0x10000 in the WBFS file\n+  // Reference: https://github.com/encounter/nod/blob/d10d376/nod/src/io/nkit.rs\n+  static constexpr u64 NKIT_OFFSET = 0x10000;\n+\n+  u8 version[8];\n+  m_files[0].file.Seek(NKIT_OFFSET, File::SeekOrigin::Begin);\n+  if (!m_files[0].file.Read(version, sizeof(version)))\n+    return false;\n+  if (std::memcmp(version, "NKIT  v2", 8) != 0)\n+    return false;\n+\n+  u8 header_meta[4];\n+  if (!m_files[0].file.Read(header_meta, sizeof(header_meta)))\n+    return false;\n+\n+  const u16 header_size =\n+      (static_cast<u16>(header_meta[0]) << 8) | header_meta[1];\n+  const u16 flags =\n+      (static_cast<u16>(header_meta[2]) << 8) | header_meta[3];\n+\n+  if (header_size < 12)\n+    return false;\n+\n+  const size_t remaining = header_size - 12;\n+  std::vector<u8> header_data(remaining);\n+  if (!m_files[0].file.Read(header_data.data(), remaining))\n+    return false;\n+\n+  size_t pos = 0;\n+  if (flags & 0x01)  // Size\n+  {\n+    if (pos + 8 > remaining)\n+      return false;\n+    m_nkit_disc_size = 0;\n+    for (int b = 0; b < 8; b++)\n+      m_nkit_disc_size = (m_nkit_disc_size << 8) | header_data[pos + b];\n+    pos += 8;\n+  }\n+  if (flags & 0x02)  // CRC32\n+    pos += 4;\n+  if (flags & 0x04)  // MD5\n+    pos += 16;\n+  if (flags & 0x08)  // SHA-1\n+    pos += 20;\n+  if (flags & 0x10)  // XXHash64\n+    pos += 8;\n+  if (flags & 0x20)  // Key\n+  {\n+    if (pos + 2 > remaining)\n+      return false;\n+    const u16 key_len =\n+        (static_cast<u16>(header_data[pos]) << 8) | header_data[pos + 1];\n+    pos += 2 + key_len;\n+  }\n+\n+  // Junk bitmap is always sized for dual-layer (covers both SL and DL discs)\n+  const u64 junk_bits_blocks =', 'path': 'Source/Core/DiscIO/WbfsBlob.cpp', 'position': 1, 'original_position': 130, 'commit_id': '81f336974c3eb2f93c05073734d2d7dc16309a6a', 'user': {'login': 'thethiny', 'id': 6018214, 'node_id': 'MDQ6VXNlcjYwMTgyMTQ=', 'avatar_url': 'https://avatars.githubusercontent.com/u/6018214?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/thethiny', 'html_url': 'https://github.com/thethiny', 'followers_url': 'https://api.github.com/users/thethiny/followers', 'following_url': 'https://api.github.com/users/thethiny/following{/other_user}', 'gists_url': 'https://api.github.com/users/thethiny/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/thethiny/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/thethiny/subscriptions', 'organizations_url': 'https://api.github.com/users/thethiny/orgs', 'repos_url': 'https://api.github.com/users/thethiny/repos', 'events_url': 'https://api.github.com/users/thethiny/events{/privacy}', 'received_events_url': 'https://api.github.com/users/thethiny/received_events', 'type': 'User', 'user_view_type': 'public', 'site_admin': False}, 'body': 'Used std::vector<u8> instead since the bitmap size is runtime-dependent (varies by disc type and block size) - std::bitset requires a compile-time size. Bit access is wrapped in NKit::IsGapJunk() so no manual bit ops in callers.', 'created_at': '2026-07-18T20:44:50Z', 'updated_at': '2026-07-18T20:44:50Z', 'html_url': 'https://github.com/dolphin-emu/dolphin/pull/14731#discussion_r3609162555', 'pull_request_url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/14731', 'author_association': 'NONE', '_links': {'self': {'href': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/comments/3609162555'}, 'html': {'href': 'https://github.com/dolphin-emu/dolphin/pull/14731#discussion_r3609162555'}, 'pull_request': {'href': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/14731'}}, 'original_commit_id': '81f336974c3eb2f93c05073734d2d7dc16309a6a', 'reactions': {'url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/comments/3609162555/reactions', 'total_count': 0, '+1': 0, '-1': 0, 'laugh': 0, 'hooray': 0, 'confused': 0, 'heart': 0, 'rocket': 0, 'eyes': 0}, 'in_reply_to_id': 3607030340}], 'type': 'gh_pull_request_review'}
2026-07-18T20:43:05.731977	{'source': 'ghhookparser', 'repo': 'dolphin-emu/dolphin', 'author': 'thethiny', 'action': 'submitted', 'pr_id': 14731, 'pr_title': 'Convert To WBFS Support', 'state': 'commented', 'url': 'https://github.com/dolphin-emu/dolphin/pull/14731#pullrequestreview-4729270577', 'comments': [{'id': 3609159791, 'node_id': 'PRRC_kwDOALCn2M7XH2hv', 'url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/comments/3609159791', 'pull_request_review_id': 4729270577, 'diff_hunk': '@@ -119,22 +144,241 @@ bool WbfsFileReader::ReadHeader()\n   return m_header.disc_table[0] != 0;\n }\n \n+bool WbfsFileReader::ReadNKitHeader()\n+{\n+  // NKit v2 header at offset 0x10000 in the WBFS file\n+  // Reference: https://github.com/encounter/nod/blob/d10d376/nod/src/io/nkit.rs\n+  static constexpr u64 NKIT_OFFSET = 0x10000;\n+\n+  u8 version[8];\n+  m_files[0].file.Seek(NKIT_OFFSET, File::SeekOrigin::Begin);\n+  if (!m_files[0].file.Read(version, sizeof(version)))\n+    return false;\n+  if (std::memcmp(version, "NKIT  v2", 8) != 0)\n+    return false;\n+\n+  u8 header_meta[4];\n+  if (!m_files[0].file.Read(header_meta, sizeof(header_meta)))\n+    return false;\n+\n+  const u16 header_size =\n+      (static_cast<u16>(header_meta[0]) << 8) | header_meta[1];\n+  const u16 flags =\n+      (static_cast<u16>(header_meta[2]) << 8) | header_meta[3];', 'path': 'Source/Core/DiscIO/WbfsBlob.cpp', 'position': 1, 'original_position': 92, 'commit_id': '81f336974c3eb2f93c05073734d2d7dc16309a6a', 'user': {'login': 'thethiny', 'id': 6018214, 'node_id': 'MDQ6VXNlcjYwMTgyMTQ=', 'avatar_url': 'https://avatars.githubusercontent.com/u/6018214?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/thethiny', 'html_url': 'https://github.com/thethiny', 'followers_url': 'https://api.github.com/users/thethiny/followers', 'following_url': 'https://api.github.com/users/thethiny/following{/other_user}', 'gists_url': 'https://api.github.com/users/thethiny/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/thethiny/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/thethiny/subscriptions', 'organizations_url': 'https://api.github.com/users/thethiny/orgs', 'repos_url': 'https://api.github.com/users/thethiny/repos', 'events_url': 'https://api.github.com/users/thethiny/events{/privacy}', 'received_events_url': 'https://api.github.com/users/thethiny/received_events', 'type': 'User', 'user_view_type': 'public', 'site_admin': False}, 'body': "Resolved, but it's worth noting that WIA/RVZ has the same issue so perhaps this needs to be considered as well? https://github.com/thethiny/dolphin/blob/24b41d58df2315831b74f76b95417f2739d02f9d/Source/Core/DiscIO/WIABlob.h#L54", 'created_at': '2026-07-18T20:43:04Z', 'updated_at': '2026-07-18T20:43:04Z', 'html_url': 'https://github.com/dolphin-emu/dolphin/pull/14731#discussion_r3609159791', 'pull_request_url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/14731', 'author_association': 'NONE', '_links': {'self': {'href': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/comments/3609159791'}, 'html': {'href': 'https://github.com/dolphin-emu/dolphin/pull/14731#discussion_r3609159791'}, 'pull_request': {'href': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/14731'}}, 'original_commit_id': '81f336974c3eb2f93c05073734d2d7dc16309a6a', 'reactions': {'url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/comments/3609159791/reactions', 'total_count': 0, '+1': 0, '-1': 0, 'laugh': 0, 'hooray': 0, 'confused': 0, 'heart': 0, 'rocket': 0, 'eyes': 0}, 'in_reply_to_id': 3606980131}], 'type': 'gh_pull_request_review'}
2026-07-18T06:37:38.101412	{'source': 'ghhookparser', 'repo': 'dolphin-emu/dolphin', 'author': 'phire', 'action': 'submitted', 'pr_id': 14731, 'pr_title': 'Convert To WBFS Support', 'state': 'commented', 'url': 'https://github.com/dolphin-emu/dolphin/pull/14731#pullrequestreview-4727896887', 'comments': [{'id': 3607799388, 'node_id': 'PRRC_kwDOALCn2M7XCqZc', 'url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/comments/3607799388', 'pull_request_review_id': 4727896887, 'diff_hunk': '@@ -119,22 +144,241 @@ bool WbfsFileReader::ReadHeader()\n   return m_header.disc_table[0] != 0;\n }\n \n+bool WbfsFileReader::ReadNKitHeader()\n+{\n+  // NKit v2 header at offset 0x10000 in the WBFS file\n+  // Reference: https://github.com/encounter/nod/blob/d10d376/nod/src/io/nkit.rs\n+  static constexpr u64 NKIT_OFFSET = 0x10000;\n+\n+  u8 version[8];\n+  m_files[0].file.Seek(NKIT_OFFSET, File::SeekOrigin::Begin);\n+  if (!m_files[0].file.Read(version, sizeof(version)))\n+    return false;\n+  if (std::memcmp(version, "NKIT  v2", 8) != 0)\n+    return false;\n+\n+  u8 header_meta[4];\n+  if (!m_files[0].file.Read(header_meta, sizeof(header_meta)))\n+    return false;\n+\n+  const u16 header_size =\n+      (static_cast<u16>(header_meta[0]) << 8) | header_meta[1];\n+  const u16 flags =\n+      (static_cast<u16>(header_meta[2]) << 8) | header_meta[3];\n+\n+  if (header_size < 12)\n+    return false;\n+\n+  const size_t remaining = header_size - 12;\n+  std::vector<u8> header_data(remaining);\n+  if (!m_files[0].file.Read(header_data.data(), remaining))\n+    return false;\n+\n+  size_t pos = 0;\n+  if (flags & 0x01)  // Size\n+  {\n+    if (pos + 8 > remaining)\n+      return false;\n+    m_nkit_disc_size = 0;\n+    for (int b = 0; b < 8; b++)\n+      m_nkit_disc_size = (m_nkit_disc_size << 8) | header_data[pos + b];\n+    pos += 8;\n+  }\n+  if (flags & 0x02)  // CRC32\n+    pos += 4;\n+  if (flags & 0x04)  // MD5\n+    pos += 16;\n+  if (flags & 0x08)  // SHA-1\n+    pos += 20;\n+  if (flags & 0x10)  // XXHash64\n+    pos += 8;\n+  if (flags & 0x20)  // Key\n+  {\n+    if (pos + 2 > remaining)\n+      return false;\n+    const u16 key_len =\n+        (static_cast<u16>(header_data[pos]) << 8) | header_data[pos + 1];\n+    pos += 2 + key_len;\n+  }\n+\n+  // Junk bitmap is always sized for dual-layer (covers both SL and DL discs)\n+  const u64 junk_bits_blocks =\n+      (DL_DVD_SIZE + m_wbfs_sector_size - 1) / m_wbfs_sector_size;\n+  const u64 junk_bits_bytes = (junk_bits_blocks + 7) / 8;\n+  m_junk_bits.resize(static_cast<size_t>(junk_bits_bytes));\n+  if (!m_files[0].file.Read(m_junk_bits.data(), static_cast<size_t>(junk_bits_bytes)))\n+    return false;\n+\n+  m_has_nkit_header = true;\n+  return true;\n+}\n+\n+bool WbfsFileReader::IsNKitJunkBlock(u64 block_index) const\n+{\n+  const size_t byte_index = static_cast<size_t>(block_index / 8);\n+  if (byte_index >= m_junk_bits.size())\n+    return false;\n+  return (m_junk_bits[byte_index] & (1 << (7 - (block_index & 7)))) != 0;\n+}\n+\n+void WbfsFileReader::GenerateJunkData(u64 disc_offset, u64 size, u8* out) const\n+{\n+  LaggedFibonacciGenerator::FillJunkData(out, static_cast<size_t>(size), disc_offset,\n+                                          m_disc_id, m_disc_num);\n+}\n+\n+void WbfsFileReader::ReadPartitionInfo()\n+{\n+  std::unique_ptr<VolumeDisc> volume = CreateDisc(CopyReader());\n+  if (!volume)\n+    return;\n+\n+  for (const Partition& partition : volume->GetPartitions())\n+  {\n+    const auto& ticket = volume->GetTicket(partition);\n+    const std::array<u8, 16> title_key = ticket.GetTitleKey();\n+\n+    u8 data_info[8];\n+    if (!Read(partition.offset + 0x2B8, 8, data_info))\n+      continue;\n+\n+    PartitionEntry entry;\n+    entry.data_offset = partition.offset + (static_cast<u64>(Common::swap32(data_info)) << 2);\n+    entry.data_size = static_cast<u64>(Common::swap32(data_info + 4)) << 2;\n+    entry.key = title_key;\n+    m_partitions.push_back(entry);\n+  }\n+}\n+\n+const WbfsFileReader::PartitionEntry* WbfsFileReader::FindPartition(u64 disc_offset) const\n+{\n+  for (const auto& p : m_partitions)\n+  {\n+    if (disc_offset >= p.data_offset && disc_offset < p.data_offset + p.data_size)\n+      return &p;\n+  }\n+  return nullptr;\n+}\n+\n+const WbfsFileReader::PartitionEntry*\n+WbfsFileReader::FindPartitionByDataOffset(u64 partition_data_offset) const\n+{\n+  for (const auto& p : m_partitions)\n+  {\n+    if (p.data_offset == partition_data_offset)\n+      return &p;\n+  }\n+  return nullptr;\n+}\n+\n+bool WbfsFileReader::SupportsReadWiiDecrypted(u64 offset, u64 size,\n+                                               u64 partition_data_offset) const\n+{\n+  return m_has_nkit_header && FindPartitionByDataOffset(partition_data_offset) != nullptr;', 'path': 'Source/Core/DiscIO/WbfsBlob.cpp', 'position': 202, 'original_position': 202, 'commit_id': '81f336974c3eb2f93c05073734d2d7dc16309a6a', 'user': {'login': 'phire', 'id': 138484, 'node_id': 'MDQ6VXNlcjEzODQ4NA==', 'avatar_url': 'https://avatars.githubusercontent.com/u/138484?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/phire', 'html_url': 'https://github.com/phire', 'followers_url': 'https://api.github.com/users/phire/followers', 'following_url': 'https://api.github.com/users/phire/following{/other_user}', 'gists_url': 'https://api.github.com/users/phire/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/phire/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/phire/subscriptions', 'organizations_url': 'https://api.github.com/users/phire/orgs', 'repos_url': 'https://api.github.com/users/phire/repos', 'events_url': 'https://api.github.com/users/phire/events{/privacy}', 'received_events_url': 'https://api.github.com/users/phire/received_events', 'type': 'User', 'user_view_type': 'public', 'site_admin': False}, 'body': 'Well... I forgot to convert from partition offset to disc offset... but you see what I mean. ', 'created_at': '2026-07-18T06:37:36Z', 'updated_at': '2026-07-18T06:37:36Z', 'html_url': 'https://github.com/dolphin-emu/dolphin/pull/14731#discussion_r3607799388', 'pull_request_url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/14731', 'author_association': 'MEMBER', '_links': {'self': {'href': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/comments/3607799388'}, 'html': {'href': 'https://github.com/dolphin-emu/dolphin/pull/14731#discussion_r3607799388'}, 'pull_request': {'href': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/14731'}}, 'original_commit_id': '81f336974c3eb2f93c05073734d2d7dc16309a6a', 'reactions': {'url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/comments/3607799388/reactions', 'total_count': 0, '+1': 0, '-1': 0, 'laugh': 0, 'hooray': 0, 'confused': 0, 'heart': 0, 'rocket': 0, 'eyes': 0}, 'in_reply_to_id': 3607691348}], 'type': 'gh_pull_request_review'}
2026-07-18T05:57:59.248761	{'source': 'ghhookparser', 'repo': 'dolphin-emu/dolphin', 'author': 'phire', 'action': 'submitted', 'pr_id': 14731, 'pr_title': 'Convert To WBFS Support', 'state': 'commented', 'url': 'https://github.com/dolphin-emu/dolphin/pull/14731#pullrequestreview-4727768011', 'comments': [{'id': 3607686059, 'node_id': 'PRRC_kwDOALCn2M7XCOur', 'url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/comments/3607686059', 'pull_request_review_id': 4727768011, 'diff_hunk': '@@ -119,22 +144,241 @@ bool WbfsFileReader::ReadHeader()\n   return m_header.disc_table[0] != 0;\n }\n \n+bool WbfsFileReader::ReadNKitHeader()\n+{\n+  // NKit v2 header at offset 0x10000 in the WBFS file\n+  // Reference: https://github.com/encounter/nod/blob/d10d376/nod/src/io/nkit.rs\n+  static constexpr u64 NKIT_OFFSET = 0x10000;\n+\n+  u8 version[8];\n+  m_files[0].file.Seek(NKIT_OFFSET, File::SeekOrigin::Begin);\n+  if (!m_files[0].file.Read(version, sizeof(version)))\n+    return false;\n+  if (std::memcmp(version, "NKIT  v2", 8) != 0)\n+    return false;\n+\n+  u8 header_meta[4];\n+  if (!m_files[0].file.Read(header_meta, sizeof(header_meta)))\n+    return false;\n+\n+  const u16 header_size =\n+      (static_cast<u16>(header_meta[0]) << 8) | header_meta[1];\n+  const u16 flags =\n+      (static_cast<u16>(header_meta[2]) << 8) | header_meta[3];\n+\n+  if (header_size < 12)\n+    return false;\n+\n+  const size_t remaining = header_size - 12;\n+  std::vector<u8> header_data(remaining);\n+  if (!m_files[0].file.Read(header_data.data(), remaining))\n+    return false;\n+\n+  size_t pos = 0;\n+  if (flags & 0x01)  // Size\n+  {\n+    if (pos + 8 > remaining)\n+      return false;\n+    m_nkit_disc_size = 0;\n+    for (int b = 0; b < 8; b++)\n+      m_nkit_disc_size = (m_nkit_disc_size << 8) | header_data[pos + b];\n+    pos += 8;\n+  }\n+  if (flags & 0x02)  // CRC32\n+    pos += 4;\n+  if (flags & 0x04)  // MD5\n+    pos += 16;\n+  if (flags & 0x08)  // SHA-1\n+    pos += 20;\n+  if (flags & 0x10)  // XXHash64\n+    pos += 8;\n+  if (flags & 0x20)  // Key\n+  {\n+    if (pos + 2 > remaining)\n+      return false;\n+    const u16 key_len =\n+        (static_cast<u16>(header_data[pos]) << 8) | header_data[pos + 1];\n+    pos += 2 + key_len;\n+  }\n+\n+  // Junk bitmap is always sized for dual-layer (covers both SL and DL discs)\n+  const u64 junk_bits_blocks =\n+      (DL_DVD_SIZE + m_wbfs_sector_size - 1) / m_wbfs_sector_size;\n+  const u64 junk_bits_bytes = (junk_bits_blocks + 7) / 8;\n+  m_junk_bits.resize(static_cast<size_t>(junk_bits_bytes));\n+  if (!m_files[0].file.Read(m_junk_bits.data(), static_cast<size_t>(junk_bits_bytes)))\n+    return false;\n+\n+  m_has_nkit_header = true;\n+  return true;\n+}\n+\n+bool WbfsFileReader::IsNKitJunkBlock(u64 block_index) const\n+{\n+  const size_t byte_index = static_cast<size_t>(block_index / 8);\n+  if (byte_index >= m_junk_bits.size())\n+    return false;\n+  return (m_junk_bits[byte_index] & (1 << (7 - (block_index & 7)))) != 0;\n+}\n+\n+void WbfsFileReader::GenerateJunkData(u64 disc_offset, u64 size, u8* out) const\n+{\n+  LaggedFibonacciGenerator::FillJunkData(out, static_cast<size_t>(size), disc_offset,\n+                                          m_disc_id, m_disc_num);\n+}\n+\n+void WbfsFileReader::ReadPartitionInfo()\n+{\n+  std::unique_ptr<VolumeDisc> volume = CreateDisc(CopyReader());\n+  if (!volume)\n+    return;\n+\n+  for (const Partition& partition : volume->GetPartitions())\n+  {\n+    const auto& ticket = volume->GetTicket(partition);\n+    const std::array<u8, 16> title_key = ticket.GetTitleKey();\n+\n+    u8 data_info[8];\n+    if (!Read(partition.offset + 0x2B8, 8, data_info))\n+      continue;\n+\n+    PartitionEntry entry;\n+    entry.data_offset = partition.offset + (static_cast<u64>(Common::swap32(data_info)) << 2);\n+    entry.data_size = static_cast<u64>(Common::swap32(data_info + 4)) << 2;\n+    entry.key = title_key;\n+    m_partitions.push_back(entry);\n+  }\n+}\n+\n+const WbfsFileReader::PartitionEntry* WbfsFileReader::FindPartition(u64 disc_offset) const\n+{\n+  for (const auto& p : m_partitions)\n+  {\n+    if (disc_offset >= p.data_offset && disc_offset < p.data_offset + p.data_size)\n+      return &p;\n+  }\n+  return nullptr;\n+}\n+\n+const WbfsFileReader::PartitionEntry*\n+WbfsFileReader::FindPartitionByDataOffset(u64 partition_data_offset) const\n+{\n+  for (const auto& p : m_partitions)\n+  {\n+    if (p.data_offset == partition_data_offset)\n+      return &p;\n+  }\n+  return nullptr;\n+}\n+\n+bool WbfsFileReader::SupportsReadWiiDecrypted(u64 offset, u64 size,\n+                                               u64 partition_data_offset) const\n+{\n+  return m_has_nkit_header && FindPartitionByDataOffset(partition_data_offset) != nullptr;\n+}\n+\n+bool WbfsFileReader::ReadWiiDecrypted(u64 offset, u64 size, u8* out_ptr,\n+                                       u64 partition_data_offset)\n+{\n+  const PartitionEntry* pe = FindPartitionByDataOffset(partition_data_offset);\n+  if (!pe)\n+    return false;\n+\n+  while (size > 0)\n+  {\n+    const u64 block_in_partition = offset / VolumeWii::BLOCK_DATA_SIZE;\n+    const u64 offset_in_block = offset % VolumeWii::BLOCK_DATA_SIZE;\n+    const u64 bytes_in_block = VolumeWii::BLOCK_DATA_SIZE - offset_in_block;\n+    const u64 read_size = std::min(bytes_in_block, size);\n+\n+    const u64 disc_offset =\n+        partition_data_offset + block_in_partition * VolumeWii::BLOCK_TOTAL_SIZE;\n+    const u64 wbfs_block = disc_offset >> m_header.wbfs_sector_shift;\n+\n+    if (wbfs_block < m_blocks_per_disc && m_wlba_table[wbfs_block] != 0)\n+    {\n+      // Stored sector: read encrypted data and decrypt\n+      u8 encrypted[VolumeWii::BLOCK_TOTAL_SIZE];\n+      u64 available;\n+      auto& file = SeekToCluster(disc_offset, &available);\n+      if (available < VolumeWii::BLOCK_TOTAL_SIZE || !file.Read(encrypted, VolumeWii::BLOCK_TOTAL_SIZE))\n+        return false;\n+      auto aes_ctx = Common::AES::CreateContextDecrypt(pe->key.data());\n+      u8 decrypted[VolumeWii::BLOCK_DATA_SIZE];\n+      VolumeWii::DecryptBlockData(encrypted, decrypted, aes_ctx.get());\n+      std::memcpy(out_ptr, decrypted + offset_in_block, static_cast<size_t>(read_size));', 'path': 'Source/Core/DiscIO/WbfsBlob.cpp', 'position': 234, 'original_position': 234, 'commit_id': '81f336974c3eb2f93c05073734d2d7dc16309a6a', 'user': {'login': 'phire', 'id': 138484, 'node_id': 'MDQ6VXNlcjEzODQ4NA==', 'avatar_url': 'https://avatars.githubusercontent.com/u/138484?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/phire', 'html_url': 'https://github.com/phire', 'followers_url': 'https://api.github.com/users/phire/followers', 'following_url': 'https://api.github.com/users/phire/following{/other_user}', 'gists_url': 'https://api.github.com/users/phire/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/phire/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/phire/subscriptions', 'organizations_url': 'https://api.github.com/users/phire/orgs', 'repos_url': 'https://api.github.com/users/phire/repos', 'events_url': 'https://api.github.com/users/phire/events{/privacy}', 'received_events_url': 'https://api.github.com/users/phire/received_events', 'type': 'User', 'user_view_type': 'public', 'site_admin': False}, 'body': "Ok, got my head around this.\n\nYou shouldn't be decrypting here, because `ReadWiiDecrypted`/`SupportsReadWiiDecrypted` are only for the case where the data format stores pre-decypted data (which wbfs doesn't). \n\nLossless wbfs can provide pre-decrypted data, but only if the following is true:\n\n - Data is inside a partition\n - The block is not referenced by `m_wlba_table`\n\nAnd then the only two possible values are junk data, or zeros.\n\nOtherwise, both should return false, and VolumeWii will fetch the encrypted data via Read. ", 'created_at': '2026-07-18T05:23:51Z', 'updated_at': '2026-07-18T05:57:57Z', 'html_url': 'https://github.com/dolphin-emu/dolphin/pull/14731#discussion_r3607686059', 'pull_request_url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/14731', 'author_association': 'MEMBER', '_links': {'self': {'href': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/comments/3607686059'}, 'html': {'href': 'https://github.com/dolphin-emu/dolphin/pull/14731#discussion_r3607686059'}, 'pull_request': {'href': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/14731'}}, 'original_commit_id': '81f336974c3eb2f93c05073734d2d7dc16309a6a', 'reactions': {'url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/comments/3607686059/reactions', 'total_count': 0, '+1': 0, '-1': 0, 'laugh': 0, 'hooray': 0, 'confused': 0, 'heart': 0, 'rocket': 0, 'eyes': 0}, 'in_reply_to_id': 3607361519}, {'id': 3607691348, 'node_id': 'PRRC_kwDOALCn2M7XCQBU', 'url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/comments/3607691348', 'pull_request_review_id': 4727768011, 'diff_hunk': '@@ -119,22 +144,241 @@ bool WbfsFileReader::ReadHeader()\n   return m_header.disc_table[0] != 0;\n }\n \n+bool WbfsFileReader::ReadNKitHeader()\n+{\n+  // NKit v2 header at offset 0x10000 in the WBFS file\n+  // Reference: https://github.com/encounter/nod/blob/d10d376/nod/src/io/nkit.rs\n+  static constexpr u64 NKIT_OFFSET = 0x10000;\n+\n+  u8 version[8];\n+  m_files[0].file.Seek(NKIT_OFFSET, File::SeekOrigin::Begin);\n+  if (!m_files[0].file.Read(version, sizeof(version)))\n+    return false;\n+  if (std::memcmp(version, "NKIT  v2", 8) != 0)\n+    return false;\n+\n+  u8 header_meta[4];\n+  if (!m_files[0].file.Read(header_meta, sizeof(header_meta)))\n+    return false;\n+\n+  const u16 header_size =\n+      (static_cast<u16>(header_meta[0]) << 8) | header_meta[1];\n+  const u16 flags =\n+      (static_cast<u16>(header_meta[2]) << 8) | header_meta[3];\n+\n+  if (header_size < 12)\n+    return false;\n+\n+  const size_t remaining = header_size - 12;\n+  std::vector<u8> header_data(remaining);\n+  if (!m_files[0].file.Read(header_data.data(), remaining))\n+    return false;\n+\n+  size_t pos = 0;\n+  if (flags & 0x01)  // Size\n+  {\n+    if (pos + 8 > remaining)\n+      return false;\n+    m_nkit_disc_size = 0;\n+    for (int b = 0; b < 8; b++)\n+      m_nkit_disc_size = (m_nkit_disc_size << 8) | header_data[pos + b];\n+    pos += 8;\n+  }\n+  if (flags & 0x02)  // CRC32\n+    pos += 4;\n+  if (flags & 0x04)  // MD5\n+    pos += 16;\n+  if (flags & 0x08)  // SHA-1\n+    pos += 20;\n+  if (flags & 0x10)  // XXHash64\n+    pos += 8;\n+  if (flags & 0x20)  // Key\n+  {\n+    if (pos + 2 > remaining)\n+      return false;\n+    const u16 key_len =\n+        (static_cast<u16>(header_data[pos]) << 8) | header_data[pos + 1];\n+    pos += 2 + key_len;\n+  }\n+\n+  // Junk bitmap is always sized for dual-layer (covers both SL and DL discs)\n+  const u64 junk_bits_blocks =\n+      (DL_DVD_SIZE + m_wbfs_sector_size - 1) / m_wbfs_sector_size;\n+  const u64 junk_bits_bytes = (junk_bits_blocks + 7) / 8;\n+  m_junk_bits.resize(static_cast<size_t>(junk_bits_bytes));\n+  if (!m_files[0].file.Read(m_junk_bits.data(), static_cast<size_t>(junk_bits_bytes)))\n+    return false;\n+\n+  m_has_nkit_header = true;\n+  return true;\n+}\n+\n+bool WbfsFileReader::IsNKitJunkBlock(u64 block_index) const\n+{\n+  const size_t byte_index = static_cast<size_t>(block_index / 8);\n+  if (byte_index >= m_junk_bits.size())\n+    return false;\n+  return (m_junk_bits[byte_index] & (1 << (7 - (block_index & 7)))) != 0;\n+}\n+\n+void WbfsFileReader::GenerateJunkData(u64 disc_offset, u64 size, u8* out) const\n+{\n+  LaggedFibonacciGenerator::FillJunkData(out, static_cast<size_t>(size), disc_offset,\n+                                          m_disc_id, m_disc_num);\n+}\n+\n+void WbfsFileReader::ReadPartitionInfo()\n+{\n+  std::unique_ptr<VolumeDisc> volume = CreateDisc(CopyReader());\n+  if (!volume)\n+    return;\n+\n+  for (const Partition& partition : volume->GetPartitions())\n+  {\n+    const auto& ticket = volume->GetTicket(partition);\n+    const std::array<u8, 16> title_key = ticket.GetTitleKey();\n+\n+    u8 data_info[8];\n+    if (!Read(partition.offset + 0x2B8, 8, data_info))\n+      continue;\n+\n+    PartitionEntry entry;\n+    entry.data_offset = partition.offset + (static_cast<u64>(Common::swap32(data_info)) << 2);\n+    entry.data_size = static_cast<u64>(Common::swap32(data_info + 4)) << 2;\n+    entry.key = title_key;\n+    m_partitions.push_back(entry);\n+  }\n+}\n+\n+const WbfsFileReader::PartitionEntry* WbfsFileReader::FindPartition(u64 disc_offset) const\n+{\n+  for (const auto& p : m_partitions)\n+  {\n+    if (disc_offset >= p.data_offset && disc_offset < p.data_offset + p.data_size)\n+      return &p;\n+  }\n+  return nullptr;\n+}\n+\n+const WbfsFileReader::PartitionEntry*\n+WbfsFileReader::FindPartitionByDataOffset(u64 partition_data_offset) const\n+{\n+  for (const auto& p : m_partitions)\n+  {\n+    if (p.data_offset == partition_data_offset)\n+      return &p;\n+  }\n+  return nullptr;\n+}\n+\n+bool WbfsFileReader::SupportsReadWiiDecrypted(u64 offset, u64 size,\n+                                               u64 partition_data_offset) const\n+{\n+  return m_has_nkit_header && FindPartitionByDataOffset(partition_data_offset) != nullptr;', 'path': 'Source/Core/DiscIO/WbfsBlob.cpp', 'position': 202, 'original_position': 202, 'commit_id': '81f336974c3eb2f93c05073734d2d7dc16309a6a', 'user': {'login': 'phire', 'id': 138484, 'node_id': 'MDQ6VXNlcjEzODQ4NA==', 'avatar_url': 'https://avatars.githubusercontent.com/u/138484?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/phire', 'html_url': 'https://github.com/phire', 'followers_url': 'https://api.github.com/users/phire/followers', 'following_url': 'https://api.github.com/users/phire/following{/other_user}', 'gists_url': 'https://api.github.com/users/phire/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/phire/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/phire/subscriptions', 'organizations_url': 'https://api.github.com/users/phire/orgs', 'repos_url': 'https://api.github.com/users/phire/repos', 'events_url': 'https://api.github.com/users/phire/events{/privacy}', 'received_events_url': 'https://api.github.com/users/phire/received_events', 'type': 'User', 'user_view_type': 'public', 'site_admin': False}, 'body': 'Only zero/junk blocks are pre-decrypted\n\n```suggestion\n  const u64 base_cluster = offset >> m_header.wbfs_sector_shift;\n  return m_has_nkit_header && m_wlba_table[offset >> m_header.wbfs_sector_shift] == 0;\n```', 'created_at': '2026-07-18T05:26:08Z', 'updated_at': '2026-07-18T05:57:57Z', 'html_url': 'https://github.com/dolphin-emu/dolphin/pull/14731#discussion_r3607691348', 'pull_request_url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/14731', 'author_association': 'MEMBER', '_links': {'self': {'href': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/comments/3607691348'}, 'html': {'href': 'https://github.com/dolphin-emu/dolphin/pull/14731#discussion_r3607691348'}, 'pull_request': {'href': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/14731'}}, 'original_commit_id': '81f336974c3eb2f93c05073734d2d7dc16309a6a', 'reactions': {'url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/comments/3607691348/reactions', 'total_count': 0, '+1': 0, '-1': 0, 'laugh': 0, 'hooray': 0, 'confused': 0, 'heart': 0, 'rocket': 0, 'eyes': 0}}, {'id': 3607711355, 'node_id': 'PRRC_kwDOALCn2M7XCU57', 'url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/comments/3607711355', 'pull_request_review_id': 4727768011, 'diff_hunk': '@@ -186,7 +430,362 @@ std::unique_ptr<WbfsFileReader> WbfsFileReader::Create(File::DirectIOFile file,\n   if (!reader->IsGood())\n     reader.reset();\n \n+  if (reader && reader->m_has_nkit_header)\n+    reader->ReadPartitionInfo();\n+\n   return reader;\n }\n \n+// Converts any disc image to WBFS with an NKit v2 header for lossless round-trips.\n+// Strips disc-level junk and partition-level junk (encrypted sectors whose decrypted\n+// content is zero or LFG padding), records a junk bitmap for reconstruction.\n+// See: https://github.com/dolphin-emu/dolphin/pull/14731\n+bool ConvertToWBFS(BlobReader* infile, const std::string& infile_path,\n+                   const std::string& outfile_path, const CompressCB& callback)\n+{\n+  ASSERT(infile->GetDataSizeType() == DataSizeType::Accurate);\n+\n+  File::DirectIOFile outfile(outfile_path, File::AccessMode::Write);\n+  if (!outfile.IsOpen())\n+  {\n+    PanicAlertFmtT(\n+        "Failed to open the output file \\"{0}\\".\\n"\n+        "Check that you have permissions to write the target folder and that the media can "\n+        "be written.",\n+        outfile_path);\n+    return false;\n+  }\n+\n+  const u64 disc_size = infile->GetDataSize();\n+\n+  // These match the values used by standard WBFS tools (wwt, WBFS Manager)\n+  static constexpr u8 hd_sector_shift = 9;\n+  static constexpr u8 wbfs_sector_shift = 21;\n+  static constexpr u64 hd_sector_size = 1ull << hd_sector_shift;\n+  static constexpr u64 wbfs_sector_size = 1ull << wbfs_sector_shift;\n+\n+  const u64 blocks_per_disc = (disc_size + wbfs_sector_size - 1) / wbfs_sector_size;\n+  const u64 disc_info_size =\n+      Common::AlignUp(WII_DISC_HEADER_SIZE + blocks_per_disc * sizeof(u16), hd_sector_size);\n+\n+  // Read disc header (first 256 bytes contain disc_id, disc_num, title, etc.)\n+  std::vector<u8> disc_header(WII_DISC_HEADER_SIZE, 0);\n+  if (!infile->Read(0, WII_DISC_HEADER_SIZE, disc_header.data()))\n+  {\n+    PanicAlertFmtT("Failed to read from the input file \\"{0}\\".", infile_path);\n+    return false;\n+  }\n+\n+  // Use Volume for partition info and decryption (per PR#14731 review)\n+  struct PartitionInfo\n+  {\n+    u64 data_offset;\n+    u64 data_size;\n+    std::unique_ptr<Common::AES::Context> aes_ctx;\n+  };\n+  std::vector<PartitionInfo> partitions;\n+\n+  std::unique_ptr<VolumeDisc> volume = CreateDisc(infile_path);\n+  if (volume)\n+  {\n+    for (const Partition& partition : volume->GetPartitions())\n+    {\n+      const auto& ticket = volume->GetTicket(partition);\n+      const std::array<u8, 16> title_key = ticket.GetTitleKey();\n+\n+      u8 data_info[8];\n+      if (!infile->Read(partition.offset + 0x2B8, 8, data_info))\n+        continue;\n+\n+      PartitionInfo info;\n+      info.data_offset = partition.offset + (static_cast<u64>(Common::swap32(data_info)) << 2);\n+      info.data_size = static_cast<u64>(Common::swap32(data_info + 4)) << 2;\n+      info.aes_ctx = Common::AES::CreateContextDecrypt(title_key.data());\n+      partitions.push_back(std::move(info));\n+    }\n+  }', 'path': 'Source/Core/DiscIO/WbfsBlob.cpp', 'position': 394, 'original_position': 394, 'commit_id': '81f336974c3eb2f93c05073734d2d7dc16309a6a', 'user': {'login': 'phire', 'id': 138484, 'node_id': 'MDQ6VXNlcjEzODQ4NA==', 'avatar_url': 'https://avatars.githubusercontent.com/u/138484?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/phire', 'html_url': 'https://github.com/phire', 'followers_url': 'https://api.github.com/users/phire/followers', 'following_url': 'https://api.github.com/users/phire/following{/other_user}', 'gists_url': 'https://api.github.com/users/phire/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/phire/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/phire/subscriptions', 'organizations_url': 'https://api.github.com/users/phire/orgs', 'repos_url': 'https://api.github.com/users/phire/repos', 'events_url': 'https://api.github.com/users/phire/events{/privacy}', 'received_events_url': 'https://api.github.com/users/phire/received_events', 'type': 'User', 'user_view_type': 'public', 'site_admin': False}, 'body': "I don't think the refactor required to just untangle `SetUpDataEntriesForWriting` is that large....\n\nAnd looking through WIA/RVZ again, I'm not sure anymore that it is a good idea to try and use one set of processing functions to handle wbfs too.... yeah, not sure. ", 'created_at': '2026-07-18T05:40:25Z', 'updated_at': '2026-07-18T05:57:57Z', 'html_url': 'https://github.com/dolphin-emu/dolphin/pull/14731#discussion_r3607711355', 'pull_request_url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/14731', 'author_association': 'MEMBER', '_links': {'self': {'href': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/comments/3607711355'}, 'html': {'href': 'https://github.com/dolphin-emu/dolphin/pull/14731#discussion_r3607711355'}, 'pull_request': {'href': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/14731'}}, 'original_commit_id': '81f336974c3eb2f93c05073734d2d7dc16309a6a', 'reactions': {'url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/comments/3607711355/reactions', 'total_count': 0, '+1': 0, '-1': 0, 'laugh': 0, 'hooray': 0, 'confused': 0, 'heart': 0, 'rocket': 0, 'eyes': 0}, 'in_reply_to_id': 3607092935}, {'id': 3607715133, 'node_id': 'PRRC_kwDOALCn2M7XCV09', 'url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/comments/3607715133', 'pull_request_review_id': 4727768011, 'diff_hunk': '@@ -186,7 +430,362 @@ std::unique_ptr<WbfsFileReader> WbfsFileReader::Create(File::DirectIOFile file,\n   if (!reader->IsGood())\n     reader.reset();\n \n+  if (reader && reader->m_has_nkit_header)\n+    reader->ReadPartitionInfo();\n+\n   return reader;\n }\n \n+// Converts any disc image to WBFS with an NKit v2 header for lossless round-trips.\n+// Strips disc-level junk and partition-level junk (encrypted sectors whose decrypted\n+// content is zero or LFG padding), records a junk bitmap for reconstruction.\n+// See: https://github.com/dolphin-emu/dolphin/pull/14731\n+bool ConvertToWBFS(BlobReader* infile, const std::string& infile_path,\n+                   const std::string& outfile_path, const CompressCB& callback)\n+{\n+  ASSERT(infile->GetDataSizeType() == DataSizeType::Accurate);\n+\n+  File::DirectIOFile outfile(outfile_path, File::AccessMode::Write);\n+  if (!outfile.IsOpen())\n+  {\n+    PanicAlertFmtT(\n+        "Failed to open the output file \\"{0}\\".\\n"\n+        "Check that you have permissions to write the target folder and that the media can "\n+        "be written.",\n+        outfile_path);\n+    return false;\n+  }\n+\n+  const u64 disc_size = infile->GetDataSize();\n+\n+  // These match the values used by standard WBFS tools (wwt, WBFS Manager)\n+  static constexpr u8 hd_sector_shift = 9;\n+  static constexpr u8 wbfs_sector_shift = 21;\n+  static constexpr u64 hd_sector_size = 1ull << hd_sector_shift;\n+  static constexpr u64 wbfs_sector_size = 1ull << wbfs_sector_shift;\n+\n+  const u64 blocks_per_disc = (disc_size + wbfs_sector_size - 1) / wbfs_sector_size;\n+  const u64 disc_info_size =\n+      Common::AlignUp(WII_DISC_HEADER_SIZE + blocks_per_disc * sizeof(u16), hd_sector_size);\n+\n+  // Read disc header (first 256 bytes contain disc_id, disc_num, title, etc.)\n+  std::vector<u8> disc_header(WII_DISC_HEADER_SIZE, 0);\n+  if (!infile->Read(0, WII_DISC_HEADER_SIZE, disc_header.data()))\n+  {\n+    PanicAlertFmtT("Failed to read from the input file \\"{0}\\".", infile_path);\n+    return false;\n+  }\n+\n+  // Use Volume for partition info and decryption (per PR#14731 review)\n+  struct PartitionInfo\n+  {\n+    u64 data_offset;\n+    u64 data_size;\n+    std::unique_ptr<Common::AES::Context> aes_ctx;\n+  };\n+  std::vector<PartitionInfo> partitions;\n+\n+  std::unique_ptr<VolumeDisc> volume = CreateDisc(infile_path);\n+  if (volume)\n+  {\n+    for (const Partition& partition : volume->GetPartitions())\n+    {\n+      const auto& ticket = volume->GetTicket(partition);\n+      const std::array<u8, 16> title_key = ticket.GetTitleKey();\n+\n+      u8 data_info[8];\n+      if (!infile->Read(partition.offset + 0x2B8, 8, data_info))\n+        continue;\n+\n+      PartitionInfo info;\n+      info.data_offset = partition.offset + (static_cast<u64>(Common::swap32(data_info)) << 2);\n+      info.data_size = static_cast<u64>(Common::swap32(data_info + 4)) << 2;\n+      info.aes_ctx = Common::AES::CreateContextDecrypt(title_key.data());\n+      partitions.push_back(std::move(info));\n+    }\n+  }\n+\n+  // NKit v2 junk bitmap: 1 bit per block, MSB-first, always sized for dual-layer\n+  const u64 junk_bits_blocks = (DL_DVD_SIZE + wbfs_sector_size - 1) / wbfs_sector_size;\n+  const u64 junk_bits_bytes = (junk_bits_blocks + 7) / 8;\n+  std::vector<u8> junk_bits(junk_bits_bytes, 0);\n+\n+  // Scan disc: classify each block as used/zero/junk, compute hashes\n+  std::vector<u8> sector_buf(wbfs_sector_size, 0);\n+  std::vector<bool> sector_used(blocks_per_disc, false);\n+  u16 used_count = 0;\n+\n+  // NKit v2 stores four hash digests for verification\n+  auto sha1_ctx = Common::SHA1::CreateContext();\n+  u32 crc = Common::StartCRC32();\n+  mbedtls_md5_context md5_ctx{};\n+  mbedtls_md5_init(&md5_ctx);\n+  mbedtls_md5_starts_ret(&md5_ctx);\n+  XXH64_state_t* xxh_state = XXH64_createState();\n+  XXH64_reset(xxh_state, 0);\n+\n+  for (u64 i = 0; i < blocks_per_disc; i++)\n+  {\n+    if (i % 100 == 0)\n+    {\n+      const bool was_cancelled =\n+          !callback(Common::GetStringT("Scanning"), static_cast<float>(i) /\n+                                                        static_cast<float>(blocks_per_disc) * 0.5f);\n+      if (was_cancelled)\n+      {\n+        XXH64_freeState(xxh_state);\n+        outfile.Close();\n+        File::Delete(outfile_path);\n+        return false;\n+      }\n+    }\n+\n+    const u64 offset = i * wbfs_sector_size;\n+    const u64 sz = std::min(wbfs_sector_size, disc_size - offset);\n+\n+    std::fill(sector_buf.begin(), sector_buf.end(), 0);\n+    if (!infile->Read(offset, sz, sector_buf.data()))\n+    {\n+      PanicAlertFmtT("Failed to read from the input file \\"{0}\\".", infile_path);\n+      XXH64_freeState(xxh_state);\n+      outfile.Close();\n+      File::Delete(outfile_path);\n+      return false;\n+    }\n+\n+    // Update all four hashes with the full disc data\n+    sha1_ctx->Update(sector_buf.data(), static_cast<size_t>(sz));\n+    crc = Common::UpdateCRC32(crc, sector_buf.data(), static_cast<size_t>(sz));\n+    mbedtls_md5_update_ret(&md5_ctx, sector_buf.data(), static_cast<size_t>(sz));\n+    XXH64_update(xxh_state, sector_buf.data(), static_cast<size_t>(sz));\n+\n+    const bool is_zero = std::ranges::all_of(sector_buf, [](u8 b) { return b == 0; });\n+    if (is_zero)\n+      continue;\n+\n+    // Check if the block matches disc-level LFG junk pattern\n+    if (LaggedFibonacciGenerator::IsJunkBlock(sector_buf.data(), static_cast<size_t>(sz),\n+                                               offset, disc_header.data(), disc_header[6]))\n+    {\n+      junk_bits[i / 8] |= static_cast<u8>(1 << (7 - (i & 7)));\n+      continue;\n+    }', 'path': 'Source/Core/DiscIO/WbfsBlob.cpp', 'position': 460, 'original_position': 460, 'commit_id': '81f336974c3eb2f93c05073734d2d7dc16309a6a', 'user': {'login': 'phire', 'id': 138484, 'node_id': 'MDQ6VXNlcjEzODQ4NA==', 'avatar_url': 'https://avatars.githubusercontent.com/u/138484?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/phire', 'html_url': 'https://github.com/phire', 'followers_url': 'https://api.github.com/users/phire/followers', 'following_url': 'https://api.github.com/users/phire/following{/other_user}', 'gists_url': 'https://api.github.com/users/phire/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/phire/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/phire/subscriptions', 'organizations_url': 'https://api.github.com/users/phire/orgs', 'repos_url': 'https://api.github.com/users/phire/repos', 'events_url': 'https://api.github.com/users/phire/events{/privacy}', 'received_events_url': 'https://api.github.com/users/phire/received_events', 'type': 'User', 'user_view_type': 'public', 'site_admin': False}, 'body': 'Yeah, I was right, I just had it backwards. \n\nThe chance that the encrypted data in a partition will be zeros, or match junk is basically zero, so no point checking. And if it did ever match by chance (or a slightly invalid disc), this code would produce an invalid wbfs file. ', 'created_at': '2026-07-18T05:43:00Z', 'updated_at': '2026-07-18T05:57:57Z', 'html_url': 'https://github.com/dolphin-emu/dolphin/pull/14731#discussion_r3607715133', 'pull_request_url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/14731', 'author_association': 'MEMBER', '_links': {'self': {'href': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/comments/3607715133'}, 'html': {'href': 'https://github.com/dolphin-emu/dolphin/pull/14731#discussion_r3607715133'}, 'pull_request': {'href': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/14731'}}, 'original_commit_id': '81f336974c3eb2f93c05073734d2d7dc16309a6a', 'reactions': {'url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/comments/3607715133/reactions', 'total_count': 0, '+1': 0, '-1': 0, 'laugh': 0, 'hooray': 0, 'confused': 0, 'heart': 0, 'rocket': 0, 'eyes': 0}, 'in_reply_to_id': 3607206463}, {'id': 3607739231, 'node_id': 'PRRC_kwDOALCn2M7XCbtf', 'url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/comments/3607739231', 'pull_request_review_id': 4727768011, 'diff_hunk': '@@ -186,7 +430,362 @@ std::unique_ptr<WbfsFileReader> WbfsFileReader::Create(File::DirectIOFile file,\n   if (!reader->IsGood())\n     reader.reset();\n \n+  if (reader && reader->m_has_nkit_header)\n+    reader->ReadPartitionInfo();\n+\n   return reader;\n }\n \n+// Converts any disc image to WBFS with an NKit v2 header for lossless round-trips.\n+// Strips disc-level junk and partition-level junk (encrypted sectors whose decrypted\n+// content is zero or LFG padding), records a junk bitmap for reconstruction.\n+// See: https://github.com/dolphin-emu/dolphin/pull/14731\n+bool ConvertToWBFS(BlobReader* infile, const std::string& infile_path,\n+                   const std::string& outfile_path, const CompressCB& callback)\n+{\n+  ASSERT(infile->GetDataSizeType() == DataSizeType::Accurate);\n+\n+  File::DirectIOFile outfile(outfile_path, File::AccessMode::Write);\n+  if (!outfile.IsOpen())\n+  {\n+    PanicAlertFmtT(\n+        "Failed to open the output file \\"{0}\\".\\n"\n+        "Check that you have permissions to write the target folder and that the media can "\n+        "be written.",\n+        outfile_path);\n+    return false;\n+  }\n+\n+  const u64 disc_size = infile->GetDataSize();\n+\n+  // These match the values used by standard WBFS tools (wwt, WBFS Manager)\n+  static constexpr u8 hd_sector_shift = 9;\n+  static constexpr u8 wbfs_sector_shift = 21;\n+  static constexpr u64 hd_sector_size = 1ull << hd_sector_shift;\n+  static constexpr u64 wbfs_sector_size = 1ull << wbfs_sector_shift;\n+\n+  const u64 blocks_per_disc = (disc_size + wbfs_sector_size - 1) / wbfs_sector_size;\n+  const u64 disc_info_size =\n+      Common::AlignUp(WII_DISC_HEADER_SIZE + blocks_per_disc * sizeof(u16), hd_sector_size);\n+\n+  // Read disc header (first 256 bytes contain disc_id, disc_num, title, etc.)\n+  std::vector<u8> disc_header(WII_DISC_HEADER_SIZE, 0);\n+  if (!infile->Read(0, WII_DISC_HEADER_SIZE, disc_header.data()))\n+  {\n+    PanicAlertFmtT("Failed to read from the input file \\"{0}\\".", infile_path);\n+    return false;\n+  }\n+\n+  // Use Volume for partition info and decryption (per PR#14731 review)\n+  struct PartitionInfo\n+  {\n+    u64 data_offset;\n+    u64 data_size;\n+    std::unique_ptr<Common::AES::Context> aes_ctx;\n+  };\n+  std::vector<PartitionInfo> partitions;\n+\n+  std::unique_ptr<VolumeDisc> volume = CreateDisc(infile_path);\n+  if (volume)\n+  {\n+    for (const Partition& partition : volume->GetPartitions())\n+    {\n+      const auto& ticket = volume->GetTicket(partition);\n+      const std::array<u8, 16> title_key = ticket.GetTitleKey();\n+\n+      u8 data_info[8];\n+      if (!infile->Read(partition.offset + 0x2B8, 8, data_info))\n+        continue;\n+\n+      PartitionInfo info;\n+      info.data_offset = partition.offset + (static_cast<u64>(Common::swap32(data_info)) << 2);\n+      info.data_size = static_cast<u64>(Common::swap32(data_info + 4)) << 2;\n+      info.aes_ctx = Common::AES::CreateContextDecrypt(title_key.data());\n+      partitions.push_back(std::move(info));\n+    }\n+  }\n+\n+  // NKit v2 junk bitmap: 1 bit per block, MSB-first, always sized for dual-layer\n+  const u64 junk_bits_blocks = (DL_DVD_SIZE + wbfs_sector_size - 1) / wbfs_sector_size;\n+  const u64 junk_bits_bytes = (junk_bits_blocks + 7) / 8;\n+  std::vector<u8> junk_bits(junk_bits_bytes, 0);\n+\n+  // Scan disc: classify each block as used/zero/junk, compute hashes\n+  std::vector<u8> sector_buf(wbfs_sector_size, 0);\n+  std::vector<bool> sector_used(blocks_per_disc, false);\n+  u16 used_count = 0;\n+\n+  // NKit v2 stores four hash digests for verification\n+  auto sha1_ctx = Common::SHA1::CreateContext();\n+  u32 crc = Common::StartCRC32();\n+  mbedtls_md5_context md5_ctx{};\n+  mbedtls_md5_init(&md5_ctx);\n+  mbedtls_md5_starts_ret(&md5_ctx);\n+  XXH64_state_t* xxh_state = XXH64_createState();\n+  XXH64_reset(xxh_state, 0);\n+\n+  for (u64 i = 0; i < blocks_per_disc; i++)\n+  {\n+    if (i % 100 == 0)\n+    {\n+      const bool was_cancelled =\n+          !callback(Common::GetStringT("Scanning"), static_cast<float>(i) /\n+                                                        static_cast<float>(blocks_per_disc) * 0.5f);\n+      if (was_cancelled)\n+      {\n+        XXH64_freeState(xxh_state);\n+        outfile.Close();\n+        File::Delete(outfile_path);\n+        return false;\n+      }\n+    }\n+\n+    const u64 offset = i * wbfs_sector_size;\n+    const u64 sz = std::min(wbfs_sector_size, disc_size - offset);\n+\n+    std::fill(sector_buf.begin(), sector_buf.end(), 0);\n+    if (!infile->Read(offset, sz, sector_buf.data()))\n+    {\n+      PanicAlertFmtT("Failed to read from the input file \\"{0}\\".", infile_path);\n+      XXH64_freeState(xxh_state);\n+      outfile.Close();\n+      File::Delete(outfile_path);\n+      return false;\n+    }\n+\n+    // Update all four hashes with the full disc data\n+    sha1_ctx->Update(sector_buf.data(), static_cast<size_t>(sz));\n+    crc = Common::UpdateCRC32(crc, sector_buf.data(), static_cast<size_t>(sz));\n+    mbedtls_md5_update_ret(&md5_ctx, sector_buf.data(), static_cast<size_t>(sz));\n+    XXH64_update(xxh_state, sector_buf.data(), static_cast<size_t>(sz));\n+\n+    const bool is_zero = std::ranges::all_of(sector_buf, [](u8 b) { return b == 0; });\n+    if (is_zero)\n+      continue;\n+\n+    // Check if the block matches disc-level LFG junk pattern\n+    if (LaggedFibonacciGenerator::IsJunkBlock(sector_buf.data(), static_cast<size_t>(sz),\n+                                               offset, disc_header.data(), disc_header[6]))\n+    {\n+      junk_bits[i / 8] |= static_cast<u8>(1 << (7 - (i & 7)));\n+      continue;\n+    }\n+\n+    // Check partition-level junk: the entire block must fall within a single partition.\n+    if (!partitions.empty())\n+    {\n+      const u32 start_sector = static_cast<u32>(offset / VolumeWii::BLOCK_TOTAL_SIZE);\n+      const u32 end_sector =\n+          static_cast<u32>((offset + sz) / VolumeWii::BLOCK_TOTAL_SIZE);\n+      const PartitionInfo* pi = nullptr;\n+      for (const auto& p : partitions)\n+      {\n+        const u32 p_start = static_cast<u32>(p.data_offset / VolumeWii::BLOCK_TOTAL_SIZE);\n+        const u32 p_end =\n+            static_cast<u32>((p.data_offset + p.data_size) / VolumeWii::BLOCK_TOTAL_SIZE);\n+        if (start_sector >= p_start && end_sector <= p_end)\n+        {\n+          pi = &p;\n+          break;\n+        }\n+      }\n+\n+      if (pi)\n+      {\n+        // All-zero and all-junk are checked separately - mixed blocks are stored.\n+        bool all_zero = true;\n+        bool all_junk = true;\n+        for (u64 sub = 0; sub < sz; sub += VolumeWii::BLOCK_TOTAL_SIZE)\n+        {\n+          const u64 abs = offset + sub;\n+          const u8* encrypted_sector = sector_buf.data() + sub;\n+          u8 decrypted[VolumeWii::BLOCK_DATA_SIZE];\n+          VolumeWii::DecryptBlockData(encrypted_sector, decrypted, pi->aes_ctx.get());', 'path': 'Source/Core/DiscIO/WbfsBlob.cpp', 'position': 491, 'original_position': 491, 'commit_id': '81f336974c3eb2f93c05073734d2d7dc16309a6a', 'user': {'login': 'phire', 'id': 138484, 'node_id': 'MDQ6VXNlcjEzODQ4NA==', 'avatar_url': 'https://avatars.githubusercontent.com/u/138484?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/phire', 'html_url': 'https://github.com/phire', 'followers_url': 'https://api.github.com/users/phire/followers', 'following_url': 'https://api.github.com/users/phire/following{/other_user}', 'gists_url': 'https://api.github.com/users/phire/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/phire/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/phire/subscriptions', 'organizations_url': 'https://api.github.com/users/phire/orgs', 'repos_url': 'https://api.github.com/users/phire/repos', 'events_url': 'https://api.github.com/users/phire/events{/privacy}', 'received_events_url': 'https://api.github.com/users/phire/received_events', 'type': 'User', 'user_view_type': 'public', 'site_admin': False}, 'body': "So, instead of decrypting manually,  it would be smarter just use the `VolumeWii` that `CreateDisc` returned, as it's `Read` method returns decrypted data. \n\nIf the underlying BlobIO is already decrypted (WIA or RVZ), it will directly return that data, skipping the dance of encrypting then decrypting. And if the data is encrypted, `VolumeWii will handle all the key stuff and decrypt it for us. \n\n*That might even allow us to avoid `SetUpDataEntriesForWriting`, as the only partition info we need at that point is the disc-offset and length.*\n\nOnly when the sector isn't filtered out (because it's zeros or junk) will we use the BlobIO::Read method to return the encrypted data (triggering encryption for RVZ/WIA formats, or just returning the data for encrypted ISOs)", 'created_at': '2026-07-18T05:57:41Z', 'updated_at': '2026-07-18T05:57:57Z', 'html_url': 'https://github.com/dolphin-emu/dolphin/pull/14731#discussion_r3607739231', 'pull_request_url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/14731', 'author_association': 'MEMBER', '_links': {'self': {'href': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/comments/3607739231'}, 'html': {'href': 'https://github.com/dolphin-emu/dolphin/pull/14731#discussion_r3607739231'}, 'pull_request': {'href': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/14731'}}, 'original_commit_id': '81f336974c3eb2f93c05073734d2d7dc16309a6a', 'reactions': {'url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/comments/3607739231/reactions', 'total_count': 0, '+1': 0, '-1': 0, 'laugh': 0, 'hooray': 0, 'confused': 0, 'heart': 0, 'rocket': 0, 'eyes': 0}}], 'type': 'gh_pull_request_review'}
2026-07-18T04:22:25.692859	{'source': 'ghhookparser', 'repo': 'dolphin-emu/dolphin', 'author': 'thethiny', 'action': 'submitted', 'pr_id': 14731, 'pr_title': 'Convert To WBFS Support', 'state': 'commented', 'url': 'https://github.com/dolphin-emu/dolphin/pull/14731#pullrequestreview-4727642644', 'comments': [{'id': 3607578967, 'node_id': 'PRRC_kwDOALCn2M7XB0lX', 'url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/comments/3607578967', 'pull_request_review_id': 4727642644, 'diff_hunk': '@@ -119,22 +144,241 @@ bool WbfsFileReader::ReadHeader()\n   return m_header.disc_table[0] != 0;\n }\n \n+bool WbfsFileReader::ReadNKitHeader()\n+{\n+  // NKit v2 header at offset 0x10000 in the WBFS file\n+  // Reference: https://github.com/encounter/nod/blob/d10d376/nod/src/io/nkit.rs\n+  static constexpr u64 NKIT_OFFSET = 0x10000;\n+\n+  u8 version[8];\n+  m_files[0].file.Seek(NKIT_OFFSET, File::SeekOrigin::Begin);\n+  if (!m_files[0].file.Read(version, sizeof(version)))\n+    return false;\n+  if (std::memcmp(version, "NKIT  v2", 8) != 0)\n+    return false;\n+\n+  u8 header_meta[4];\n+  if (!m_files[0].file.Read(header_meta, sizeof(header_meta)))\n+    return false;\n+\n+  const u16 header_size =\n+      (static_cast<u16>(header_meta[0]) << 8) | header_meta[1];\n+  const u16 flags =\n+      (static_cast<u16>(header_meta[2]) << 8) | header_meta[3];\n+\n+  if (header_size < 12)\n+    return false;\n+\n+  const size_t remaining = header_size - 12;\n+  std::vector<u8> header_data(remaining);\n+  if (!m_files[0].file.Read(header_data.data(), remaining))\n+    return false;\n+\n+  size_t pos = 0;\n+  if (flags & 0x01)  // Size\n+  {\n+    if (pos + 8 > remaining)\n+      return false;\n+    m_nkit_disc_size = 0;\n+    for (int b = 0; b < 8; b++)\n+      m_nkit_disc_size = (m_nkit_disc_size << 8) | header_data[pos + b];\n+    pos += 8;\n+  }\n+  if (flags & 0x02)  // CRC32\n+    pos += 4;\n+  if (flags & 0x04)  // MD5\n+    pos += 16;\n+  if (flags & 0x08)  // SHA-1\n+    pos += 20;\n+  if (flags & 0x10)  // XXHash64\n+    pos += 8;\n+  if (flags & 0x20)  // Key\n+  {\n+    if (pos + 2 > remaining)\n+      return false;\n+    const u16 key_len =\n+        (static_cast<u16>(header_data[pos]) << 8) | header_data[pos + 1];\n+    pos += 2 + key_len;\n+  }\n+\n+  // Junk bitmap is always sized for dual-layer (covers both SL and DL discs)\n+  const u64 junk_bits_blocks =\n+      (DL_DVD_SIZE + m_wbfs_sector_size - 1) / m_wbfs_sector_size;\n+  const u64 junk_bits_bytes = (junk_bits_blocks + 7) / 8;\n+  m_junk_bits.resize(static_cast<size_t>(junk_bits_bytes));\n+  if (!m_files[0].file.Read(m_junk_bits.data(), static_cast<size_t>(junk_bits_bytes)))\n+    return false;\n+\n+  m_has_nkit_header = true;\n+  return true;\n+}\n+\n+bool WbfsFileReader::IsNKitJunkBlock(u64 block_index) const\n+{\n+  const size_t byte_index = static_cast<size_t>(block_index / 8);\n+  if (byte_index >= m_junk_bits.size())\n+    return false;\n+  return (m_junk_bits[byte_index] & (1 << (7 - (block_index & 7)))) != 0;\n+}\n+\n+void WbfsFileReader::GenerateJunkData(u64 disc_offset, u64 size, u8* out) const\n+{\n+  LaggedFibonacciGenerator::FillJunkData(out, static_cast<size_t>(size), disc_offset,\n+                                          m_disc_id, m_disc_num);\n+}\n+\n+void WbfsFileReader::ReadPartitionInfo()\n+{\n+  std::unique_ptr<VolumeDisc> volume = CreateDisc(CopyReader());\n+  if (!volume)\n+    return;\n+\n+  for (const Partition& partition : volume->GetPartitions())\n+  {\n+    const auto& ticket = volume->GetTicket(partition);\n+    const std::array<u8, 16> title_key = ticket.GetTitleKey();\n+\n+    u8 data_info[8];\n+    if (!Read(partition.offset + 0x2B8, 8, data_info))\n+      continue;\n+\n+    PartitionEntry entry;\n+    entry.data_offset = partition.offset + (static_cast<u64>(Common::swap32(data_info)) << 2);\n+    entry.data_size = static_cast<u64>(Common::swap32(data_info + 4)) << 2;\n+    entry.key = title_key;\n+    m_partitions.push_back(entry);\n+  }\n+}\n+\n+const WbfsFileReader::PartitionEntry* WbfsFileReader::FindPartition(u64 disc_offset) const\n+{\n+  for (const auto& p : m_partitions)\n+  {\n+    if (disc_offset >= p.data_offset && disc_offset < p.data_offset + p.data_size)\n+      return &p;\n+  }\n+  return nullptr;\n+}\n+\n+const WbfsFileReader::PartitionEntry*\n+WbfsFileReader::FindPartitionByDataOffset(u64 partition_data_offset) const\n+{\n+  for (const auto& p : m_partitions)\n+  {\n+    if (p.data_offset == partition_data_offset)\n+      return &p;\n+  }\n+  return nullptr;\n+}\n+\n+bool WbfsFileReader::SupportsReadWiiDecrypted(u64 offset, u64 size,\n+                                               u64 partition_data_offset) const\n+{\n+  return m_has_nkit_header && FindPartitionByDataOffset(partition_data_offset) != nullptr;\n+}\n+\n+bool WbfsFileReader::ReadWiiDecrypted(u64 offset, u64 size, u8* out_ptr,\n+                                       u64 partition_data_offset)\n+{\n+  const PartitionEntry* pe = FindPartitionByDataOffset(partition_data_offset);\n+  if (!pe)\n+    return false;\n+\n+  while (size > 0)\n+  {\n+    const u64 block_in_partition = offset / VolumeWii::BLOCK_DATA_SIZE;\n+    const u64 offset_in_block = offset % VolumeWii::BLOCK_DATA_SIZE;\n+    const u64 bytes_in_block = VolumeWii::BLOCK_DATA_SIZE - offset_in_block;\n+    const u64 read_size = std::min(bytes_in_block, size);\n+\n+    const u64 disc_offset =\n+        partition_data_offset + block_in_partition * VolumeWii::BLOCK_TOTAL_SIZE;\n+    const u64 wbfs_block = disc_offset >> m_header.wbfs_sector_shift;\n+\n+    if (wbfs_block < m_blocks_per_disc && m_wlba_table[wbfs_block] != 0)\n+    {\n+      // Stored sector: read encrypted data and decrypt\n+      u8 encrypted[VolumeWii::BLOCK_TOTAL_SIZE];\n+      u64 available;\n+      auto& file = SeekToCluster(disc_offset, &available);\n+      if (available < VolumeWii::BLOCK_TOTAL_SIZE || !file.Read(encrypted, VolumeWii::BLOCK_TOTAL_SIZE))\n+        return false;\n+      auto aes_ctx = Common::AES::CreateContextDecrypt(pe->key.data());\n+      u8 decrypted[VolumeWii::BLOCK_DATA_SIZE];\n+      VolumeWii::DecryptBlockData(encrypted, decrypted, aes_ctx.get());\n+      std::memcpy(out_ptr, decrypted + offset_in_block, static_cast<size_t>(read_size));', 'path': 'Source/Core/DiscIO/WbfsBlob.cpp', 'position': 234, 'original_position': 234, 'commit_id': '81f336974c3eb2f93c05073734d2d7dc16309a6a', 'user': {'login': 'thethiny', 'id': 6018214, 'node_id': 'MDQ6VXNlcjYwMTgyMTQ=', 'avatar_url': 'https://avatars.githubusercontent.com/u/6018214?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/thethiny', 'html_url': 'https://github.com/thethiny', 'followers_url': 'https://api.github.com/users/thethiny/followers', 'following_url': 'https://api.github.com/users/thethiny/following{/other_user}', 'gists_url': 'https://api.github.com/users/thethiny/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/thethiny/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/thethiny/subscriptions', 'organizations_url': 'https://api.github.com/users/thethiny/orgs', 'repos_url': 'https://api.github.com/users/thethiny/repos', 'events_url': 'https://api.github.com/users/thethiny/events{/privacy}', 'received_events_url': 'https://api.github.com/users/thethiny/received_events', 'type': 'User', 'user_view_type': 'public', 'site_admin': False}, 'body': 'All is cool 🙏🏻 I appreciate you taking the time to review my code! ', 'created_at': '2026-07-18T04:22:23Z', 'updated_at': '2026-07-18T04:22:24Z', 'html_url': 'https://github.com/dolphin-emu/dolphin/pull/14731#discussion_r3607578967', 'pull_request_url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/14731', 'author_association': 'NONE', '_links': {'self': {'href': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/comments/3607578967'}, 'html': {'href': 'https://github.com/dolphin-emu/dolphin/pull/14731#discussion_r3607578967'}, 'pull_request': {'href': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/14731'}}, 'original_commit_id': '81f336974c3eb2f93c05073734d2d7dc16309a6a', 'reactions': {'url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/comments/3607578967/reactions', 'total_count': 0, '+1': 0, '-1': 0, 'laugh': 0, 'hooray': 0, 'confused': 0, 'heart': 0, 'rocket': 0, 'eyes': 0}, 'in_reply_to_id': 3607361519}], 'type': 'gh_pull_request_review'}
2026-07-18T04:12:49.807563	{'source': 'ghhookparser', 'repo': 'dolphin-emu/dolphin', 'author': 'phire', 'action': 'submitted', 'pr_id': 14731, 'pr_title': 'Convert To WBFS Support', 'state': 'commented', 'url': 'https://github.com/dolphin-emu/dolphin/pull/14731#pullrequestreview-4727627612', 'comments': [{'id': 3607565686, 'node_id': 'PRRC_kwDOALCn2M7XBxV2', 'url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/comments/3607565686', 'pull_request_review_id': 4727627612, 'diff_hunk': '@@ -119,22 +144,241 @@ bool WbfsFileReader::ReadHeader()\n   return m_header.disc_table[0] != 0;\n }\n \n+bool WbfsFileReader::ReadNKitHeader()\n+{\n+  // NKit v2 header at offset 0x10000 in the WBFS file\n+  // Reference: https://github.com/encounter/nod/blob/d10d376/nod/src/io/nkit.rs\n+  static constexpr u64 NKIT_OFFSET = 0x10000;\n+\n+  u8 version[8];\n+  m_files[0].file.Seek(NKIT_OFFSET, File::SeekOrigin::Begin);\n+  if (!m_files[0].file.Read(version, sizeof(version)))\n+    return false;\n+  if (std::memcmp(version, "NKIT  v2", 8) != 0)\n+    return false;\n+\n+  u8 header_meta[4];\n+  if (!m_files[0].file.Read(header_meta, sizeof(header_meta)))\n+    return false;\n+\n+  const u16 header_size =\n+      (static_cast<u16>(header_meta[0]) << 8) | header_meta[1];\n+  const u16 flags =\n+      (static_cast<u16>(header_meta[2]) << 8) | header_meta[3];\n+\n+  if (header_size < 12)\n+    return false;\n+\n+  const size_t remaining = header_size - 12;\n+  std::vector<u8> header_data(remaining);\n+  if (!m_files[0].file.Read(header_data.data(), remaining))\n+    return false;\n+\n+  size_t pos = 0;\n+  if (flags & 0x01)  // Size\n+  {\n+    if (pos + 8 > remaining)\n+      return false;\n+    m_nkit_disc_size = 0;\n+    for (int b = 0; b < 8; b++)\n+      m_nkit_disc_size = (m_nkit_disc_size << 8) | header_data[pos + b];\n+    pos += 8;\n+  }\n+  if (flags & 0x02)  // CRC32\n+    pos += 4;\n+  if (flags & 0x04)  // MD5\n+    pos += 16;\n+  if (flags & 0x08)  // SHA-1\n+    pos += 20;\n+  if (flags & 0x10)  // XXHash64\n+    pos += 8;\n+  if (flags & 0x20)  // Key\n+  {\n+    if (pos + 2 > remaining)\n+      return false;\n+    const u16 key_len =\n+        (static_cast<u16>(header_data[pos]) << 8) | header_data[pos + 1];\n+    pos += 2 + key_len;\n+  }\n+\n+  // Junk bitmap is always sized for dual-layer (covers both SL and DL discs)\n+  const u64 junk_bits_blocks =\n+      (DL_DVD_SIZE + m_wbfs_sector_size - 1) / m_wbfs_sector_size;\n+  const u64 junk_bits_bytes = (junk_bits_blocks + 7) / 8;\n+  m_junk_bits.resize(static_cast<size_t>(junk_bits_bytes));\n+  if (!m_files[0].file.Read(m_junk_bits.data(), static_cast<size_t>(junk_bits_bytes)))\n+    return false;\n+\n+  m_has_nkit_header = true;\n+  return true;\n+}\n+\n+bool WbfsFileReader::IsNKitJunkBlock(u64 block_index) const\n+{\n+  const size_t byte_index = static_cast<size_t>(block_index / 8);\n+  if (byte_index >= m_junk_bits.size())\n+    return false;\n+  return (m_junk_bits[byte_index] & (1 << (7 - (block_index & 7)))) != 0;\n+}\n+\n+void WbfsFileReader::GenerateJunkData(u64 disc_offset, u64 size, u8* out) const\n+{\n+  LaggedFibonacciGenerator::FillJunkData(out, static_cast<size_t>(size), disc_offset,\n+                                          m_disc_id, m_disc_num);\n+}\n+\n+void WbfsFileReader::ReadPartitionInfo()\n+{\n+  std::unique_ptr<VolumeDisc> volume = CreateDisc(CopyReader());\n+  if (!volume)\n+    return;\n+\n+  for (const Partition& partition : volume->GetPartitions())\n+  {\n+    const auto& ticket = volume->GetTicket(partition);\n+    const std::array<u8, 16> title_key = ticket.GetTitleKey();\n+\n+    u8 data_info[8];\n+    if (!Read(partition.offset + 0x2B8, 8, data_info))\n+      continue;\n+\n+    PartitionEntry entry;\n+    entry.data_offset = partition.offset + (static_cast<u64>(Common::swap32(data_info)) << 2);\n+    entry.data_size = static_cast<u64>(Common::swap32(data_info + 4)) << 2;\n+    entry.key = title_key;\n+    m_partitions.push_back(entry);\n+  }\n+}\n+\n+const WbfsFileReader::PartitionEntry* WbfsFileReader::FindPartition(u64 disc_offset) const\n+{\n+  for (const auto& p : m_partitions)\n+  {\n+    if (disc_offset >= p.data_offset && disc_offset < p.data_offset + p.data_size)\n+      return &p;\n+  }\n+  return nullptr;\n+}\n+\n+const WbfsFileReader::PartitionEntry*\n+WbfsFileReader::FindPartitionByDataOffset(u64 partition_data_offset) const\n+{\n+  for (const auto& p : m_partitions)\n+  {\n+    if (p.data_offset == partition_data_offset)\n+      return &p;\n+  }\n+  return nullptr;\n+}\n+\n+bool WbfsFileReader::SupportsReadWiiDecrypted(u64 offset, u64 size,\n+                                               u64 partition_data_offset) const\n+{\n+  return m_has_nkit_header && FindPartitionByDataOffset(partition_data_offset) != nullptr;\n+}\n+\n+bool WbfsFileReader::ReadWiiDecrypted(u64 offset, u64 size, u8* out_ptr,\n+                                       u64 partition_data_offset)\n+{\n+  const PartitionEntry* pe = FindPartitionByDataOffset(partition_data_offset);\n+  if (!pe)\n+    return false;\n+\n+  while (size > 0)\n+  {\n+    const u64 block_in_partition = offset / VolumeWii::BLOCK_DATA_SIZE;\n+    const u64 offset_in_block = offset % VolumeWii::BLOCK_DATA_SIZE;\n+    const u64 bytes_in_block = VolumeWii::BLOCK_DATA_SIZE - offset_in_block;\n+    const u64 read_size = std::min(bytes_in_block, size);\n+\n+    const u64 disc_offset =\n+        partition_data_offset + block_in_partition * VolumeWii::BLOCK_TOTAL_SIZE;\n+    const u64 wbfs_block = disc_offset >> m_header.wbfs_sector_shift;\n+\n+    if (wbfs_block < m_blocks_per_disc && m_wlba_table[wbfs_block] != 0)\n+    {\n+      // Stored sector: read encrypted data and decrypt\n+      u8 encrypted[VolumeWii::BLOCK_TOTAL_SIZE];\n+      u64 available;\n+      auto& file = SeekToCluster(disc_offset, &available);\n+      if (available < VolumeWii::BLOCK_TOTAL_SIZE || !file.Read(encrypted, VolumeWii::BLOCK_TOTAL_SIZE))\n+        return false;\n+      auto aes_ctx = Common::AES::CreateContextDecrypt(pe->key.data());\n+      u8 decrypted[VolumeWii::BLOCK_DATA_SIZE];\n+      VolumeWii::DecryptBlockData(encrypted, decrypted, aes_ctx.get());\n+      std::memcpy(out_ptr, decrypted + offset_in_block, static_cast<size_t>(read_size));', 'path': 'Source/Core/DiscIO/WbfsBlob.cpp', 'position': 234, 'original_position': 234, 'commit_id': '81f336974c3eb2f93c05073734d2d7dc16309a6a', 'user': {'login': 'phire', 'id': 138484, 'node_id': 'MDQ6VXNlcjEzODQ4NA==', 'avatar_url': 'https://avatars.githubusercontent.com/u/138484?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/phire', 'html_url': 'https://github.com/phire', 'followers_url': 'https://api.github.com/users/phire/followers', 'following_url': 'https://api.github.com/users/phire/following{/other_user}', 'gists_url': 'https://api.github.com/users/phire/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/phire/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/phire/subscriptions', 'organizations_url': 'https://api.github.com/users/phire/orgs', 'repos_url': 'https://api.github.com/users/phire/repos', 'events_url': 'https://api.github.com/users/phire/events{/privacy}', 'received_events_url': 'https://api.github.com/users/phire/received_events', 'type': 'User', 'user_view_type': 'public', 'site_admin': False}, 'body': 'Wait... I might be confused about wbfs data being decrypted. I probably got this all wrong, sorry. ', 'created_at': '2026-07-18T04:12:47Z', 'updated_at': '2026-07-18T04:12:48Z', 'html_url': 'https://github.com/dolphin-emu/dolphin/pull/14731#discussion_r3607565686', 'pull_request_url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/14731', 'author_association': 'MEMBER', '_links': {'self': {'href': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/comments/3607565686'}, 'html': {'href': 'https://github.com/dolphin-emu/dolphin/pull/14731#discussion_r3607565686'}, 'pull_request': {'href': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/14731'}}, 'original_commit_id': '81f336974c3eb2f93c05073734d2d7dc16309a6a', 'reactions': {'url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/comments/3607565686/reactions', 'total_count': 0, '+1': 0, '-1': 0, 'laugh': 0, 'hooray': 0, 'confused': 0, 'heart': 0, 'rocket': 0, 'eyes': 0}, 'in_reply_to_id': 3607361519}], 'type': 'gh_pull_request_review'}
2026-07-18T04:08:45.770850	{'source': 'ghhookparser', 'repo': 'dolphin-emu/dolphin', 'author': 'thethiny', 'action': 'submitted', 'pr_id': 14731, 'pr_title': 'Convert To WBFS Support', 'state': 'commented', 'url': 'https://github.com/dolphin-emu/dolphin/pull/14731#pullrequestreview-4727621130', 'comments': [{'id': 3607558820, 'node_id': 'PRRC_kwDOALCn2M7XBvqk', 'url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/comments/3607558820', 'pull_request_review_id': 4727621130, 'diff_hunk': '@@ -186,7 +430,362 @@ std::unique_ptr<WbfsFileReader> WbfsFileReader::Create(File::DirectIOFile file,\n   if (!reader->IsGood())\n     reader.reset();\n \n+  if (reader && reader->m_has_nkit_header)\n+    reader->ReadPartitionInfo();\n+\n   return reader;\n }\n \n+// Converts any disc image to WBFS with an NKit v2 header for lossless round-trips.\n+// Strips disc-level junk and partition-level junk (encrypted sectors whose decrypted\n+// content is zero or LFG padding), records a junk bitmap for reconstruction.\n+// See: https://github.com/dolphin-emu/dolphin/pull/14731\n+bool ConvertToWBFS(BlobReader* infile, const std::string& infile_path,\n+                   const std::string& outfile_path, const CompressCB& callback)\n+{\n+  ASSERT(infile->GetDataSizeType() == DataSizeType::Accurate);\n+\n+  File::DirectIOFile outfile(outfile_path, File::AccessMode::Write);\n+  if (!outfile.IsOpen())\n+  {\n+    PanicAlertFmtT(\n+        "Failed to open the output file \\"{0}\\".\\n"\n+        "Check that you have permissions to write the target folder and that the media can "\n+        "be written.",\n+        outfile_path);\n+    return false;\n+  }\n+\n+  const u64 disc_size = infile->GetDataSize();\n+\n+  // These match the values used by standard WBFS tools (wwt, WBFS Manager)\n+  static constexpr u8 hd_sector_shift = 9;\n+  static constexpr u8 wbfs_sector_shift = 21;\n+  static constexpr u64 hd_sector_size = 1ull << hd_sector_shift;\n+  static constexpr u64 wbfs_sector_size = 1ull << wbfs_sector_shift;\n+\n+  const u64 blocks_per_disc = (disc_size + wbfs_sector_size - 1) / wbfs_sector_size;\n+  const u64 disc_info_size =\n+      Common::AlignUp(WII_DISC_HEADER_SIZE + blocks_per_disc * sizeof(u16), hd_sector_size);\n+\n+  // Read disc header (first 256 bytes contain disc_id, disc_num, title, etc.)\n+  std::vector<u8> disc_header(WII_DISC_HEADER_SIZE, 0);\n+  if (!infile->Read(0, WII_DISC_HEADER_SIZE, disc_header.data()))\n+  {\n+    PanicAlertFmtT("Failed to read from the input file \\"{0}\\".", infile_path);\n+    return false;\n+  }\n+\n+  // Use Volume for partition info and decryption (per PR#14731 review)\n+  struct PartitionInfo\n+  {\n+    u64 data_offset;\n+    u64 data_size;\n+    std::unique_ptr<Common::AES::Context> aes_ctx;\n+  };\n+  std::vector<PartitionInfo> partitions;\n+\n+  std::unique_ptr<VolumeDisc> volume = CreateDisc(infile_path);\n+  if (volume)\n+  {\n+    for (const Partition& partition : volume->GetPartitions())\n+    {\n+      const auto& ticket = volume->GetTicket(partition);\n+      const std::array<u8, 16> title_key = ticket.GetTitleKey();\n+\n+      u8 data_info[8];\n+      if (!infile->Read(partition.offset + 0x2B8, 8, data_info))\n+        continue;\n+\n+      PartitionInfo info;\n+      info.data_offset = partition.offset + (static_cast<u64>(Common::swap32(data_info)) << 2);\n+      info.data_size = static_cast<u64>(Common::swap32(data_info + 4)) << 2;\n+      info.aes_ctx = Common::AES::CreateContextDecrypt(title_key.data());\n+      partitions.push_back(std::move(info));\n+    }\n+  }\n+\n+  // NKit v2 junk bitmap: 1 bit per block, MSB-first, always sized for dual-layer\n+  const u64 junk_bits_blocks = (DL_DVD_SIZE + wbfs_sector_size - 1) / wbfs_sector_size;\n+  const u64 junk_bits_bytes = (junk_bits_blocks + 7) / 8;\n+  std::vector<u8> junk_bits(junk_bits_bytes, 0);\n+\n+  // Scan disc: classify each block as used/zero/junk, compute hashes\n+  std::vector<u8> sector_buf(wbfs_sector_size, 0);\n+  std::vector<bool> sector_used(blocks_per_disc, false);\n+  u16 used_count = 0;\n+\n+  // NKit v2 stores four hash digests for verification\n+  auto sha1_ctx = Common::SHA1::CreateContext();\n+  u32 crc = Common::StartCRC32();\n+  mbedtls_md5_context md5_ctx{};\n+  mbedtls_md5_init(&md5_ctx);\n+  mbedtls_md5_starts_ret(&md5_ctx);\n+  XXH64_state_t* xxh_state = XXH64_createState();\n+  XXH64_reset(xxh_state, 0);\n+\n+  for (u64 i = 0; i < blocks_per_disc; i++)\n+  {\n+    if (i % 100 == 0)\n+    {\n+      const bool was_cancelled =\n+          !callback(Common::GetStringT("Scanning"), static_cast<float>(i) /\n+                                                        static_cast<float>(blocks_per_disc) * 0.5f);\n+      if (was_cancelled)\n+      {\n+        XXH64_freeState(xxh_state);\n+        outfile.Close();\n+        File::Delete(outfile_path);\n+        return false;\n+      }\n+    }\n+\n+    const u64 offset = i * wbfs_sector_size;\n+    const u64 sz = std::min(wbfs_sector_size, disc_size - offset);\n+\n+    std::fill(sector_buf.begin(), sector_buf.end(), 0);\n+    if (!infile->Read(offset, sz, sector_buf.data()))\n+    {\n+      PanicAlertFmtT("Failed to read from the input file \\"{0}\\".", infile_path);\n+      XXH64_freeState(xxh_state);\n+      outfile.Close();\n+      File::Delete(outfile_path);\n+      return false;\n+    }\n+\n+    // Update all four hashes with the full disc data\n+    sha1_ctx->Update(sector_buf.data(), static_cast<size_t>(sz));\n+    crc = Common::UpdateCRC32(crc, sector_buf.data(), static_cast<size_t>(sz));\n+    mbedtls_md5_update_ret(&md5_ctx, sector_buf.data(), static_cast<size_t>(sz));\n+    XXH64_update(xxh_state, sector_buf.data(), static_cast<size_t>(sz));\n+\n+    const bool is_zero = std::ranges::all_of(sector_buf, [](u8 b) { return b == 0; });\n+    if (is_zero)\n+      continue;\n+\n+    // Check if the block matches disc-level LFG junk pattern\n+    if (LaggedFibonacciGenerator::IsJunkBlock(sector_buf.data(), static_cast<size_t>(sz),\n+                                               offset, disc_header.data(), disc_header[6]))\n+    {\n+      junk_bits[i / 8] |= static_cast<u8>(1 << (7 - (i & 7)));\n+      continue;\n+    }', 'path': 'Source/Core/DiscIO/WbfsBlob.cpp', 'position': 460, 'original_position': 460, 'commit_id': '81f336974c3eb2f93c05073734d2d7dc16309a6a', 'user': {'login': 'thethiny', 'id': 6018214, 'node_id': 'MDQ6VXNlcjYwMTgyMTQ=', 'avatar_url': 'https://avatars.githubusercontent.com/u/6018214?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/thethiny', 'html_url': 'https://github.com/thethiny', 'followers_url': 'https://api.github.com/users/thethiny/followers', 'following_url': 'https://api.github.com/users/thethiny/following{/other_user}', 'gists_url': 'https://api.github.com/users/thethiny/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/thethiny/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/thethiny/subscriptions', 'organizations_url': 'https://api.github.com/users/thethiny/orgs', 'repos_url': 'https://api.github.com/users/thethiny/repos', 'events_url': 'https://api.github.com/users/thethiny/events{/privacy}', 'received_events_url': 'https://api.github.com/users/thethiny/received_events', 'type': 'User', 'user_view_type': 'public', 'site_admin': False}, 'body': "Alright this makes sense then. Yes I'm using `BlobReader::Read` which returns the raw data (no decryption) but you were referring to `Volume::Read` which handles decryption. I think I will proceed with the fixes you've mentioned, and will keep this decryption vs encryption thing as a commit of its own once we agree on how to tackle this.", 'created_at': '2026-07-18T04:08:44Z', 'updated_at': '2026-07-18T04:08:44Z', 'html_url': 'https://github.com/dolphin-emu/dolphin/pull/14731#discussion_r3607558820', 'pull_request_url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/14731', 'author_association': 'NONE', '_links': {'self': {'href': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/comments/3607558820'}, 'html': {'href': 'https://github.com/dolphin-emu/dolphin/pull/14731#discussion_r3607558820'}, 'pull_request': {'href': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/14731'}}, 'original_commit_id': '81f336974c3eb2f93c05073734d2d7dc16309a6a', 'reactions': {'url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/comments/3607558820/reactions', 'total_count': 0, '+1': 0, '-1': 0, 'laugh': 0, 'hooray': 0, 'confused': 0, 'heart': 0, 'rocket': 0, 'eyes': 0}, 'in_reply_to_id': 3607206463}], 'type': 'gh_pull_request_review'}
2026-07-18T04:05:38.946059	{'source': 'ghhookparser', 'repo': 'dolphin-emu/dolphin', 'author': 'thethiny', 'action': 'submitted', 'pr_id': 14731, 'pr_title': 'Convert To WBFS Support', 'state': 'commented', 'url': 'https://github.com/dolphin-emu/dolphin/pull/14731#pullrequestreview-4727613279', 'comments': [{'id': 3607550881, 'node_id': 'PRRC_kwDOALCn2M7XBtuh', 'url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/comments/3607550881', 'pull_request_review_id': 4727613279, 'diff_hunk': '@@ -119,22 +144,241 @@ bool WbfsFileReader::ReadHeader()\n   return m_header.disc_table[0] != 0;\n }\n \n+bool WbfsFileReader::ReadNKitHeader()\n+{\n+  // NKit v2 header at offset 0x10000 in the WBFS file\n+  // Reference: https://github.com/encounter/nod/blob/d10d376/nod/src/io/nkit.rs\n+  static constexpr u64 NKIT_OFFSET = 0x10000;\n+\n+  u8 version[8];\n+  m_files[0].file.Seek(NKIT_OFFSET, File::SeekOrigin::Begin);\n+  if (!m_files[0].file.Read(version, sizeof(version)))\n+    return false;\n+  if (std::memcmp(version, "NKIT  v2", 8) != 0)\n+    return false;\n+\n+  u8 header_meta[4];\n+  if (!m_files[0].file.Read(header_meta, sizeof(header_meta)))\n+    return false;\n+\n+  const u16 header_size =\n+      (static_cast<u16>(header_meta[0]) << 8) | header_meta[1];\n+  const u16 flags =\n+      (static_cast<u16>(header_meta[2]) << 8) | header_meta[3];\n+\n+  if (header_size < 12)\n+    return false;\n+\n+  const size_t remaining = header_size - 12;\n+  std::vector<u8> header_data(remaining);\n+  if (!m_files[0].file.Read(header_data.data(), remaining))\n+    return false;\n+\n+  size_t pos = 0;\n+  if (flags & 0x01)  // Size\n+  {\n+    if (pos + 8 > remaining)\n+      return false;\n+    m_nkit_disc_size = 0;\n+    for (int b = 0; b < 8; b++)\n+      m_nkit_disc_size = (m_nkit_disc_size << 8) | header_data[pos + b];\n+    pos += 8;\n+  }\n+  if (flags & 0x02)  // CRC32\n+    pos += 4;\n+  if (flags & 0x04)  // MD5\n+    pos += 16;\n+  if (flags & 0x08)  // SHA-1\n+    pos += 20;\n+  if (flags & 0x10)  // XXHash64\n+    pos += 8;\n+  if (flags & 0x20)  // Key\n+  {\n+    if (pos + 2 > remaining)\n+      return false;\n+    const u16 key_len =\n+        (static_cast<u16>(header_data[pos]) << 8) | header_data[pos + 1];\n+    pos += 2 + key_len;\n+  }\n+\n+  // Junk bitmap is always sized for dual-layer (covers both SL and DL discs)\n+  const u64 junk_bits_blocks =\n+      (DL_DVD_SIZE + m_wbfs_sector_size - 1) / m_wbfs_sector_size;\n+  const u64 junk_bits_bytes = (junk_bits_blocks + 7) / 8;\n+  m_junk_bits.resize(static_cast<size_t>(junk_bits_bytes));\n+  if (!m_files[0].file.Read(m_junk_bits.data(), static_cast<size_t>(junk_bits_bytes)))\n+    return false;\n+\n+  m_has_nkit_header = true;\n+  return true;\n+}\n+\n+bool WbfsFileReader::IsNKitJunkBlock(u64 block_index) const\n+{\n+  const size_t byte_index = static_cast<size_t>(block_index / 8);\n+  if (byte_index >= m_junk_bits.size())\n+    return false;\n+  return (m_junk_bits[byte_index] & (1 << (7 - (block_index & 7)))) != 0;\n+}\n+\n+void WbfsFileReader::GenerateJunkData(u64 disc_offset, u64 size, u8* out) const\n+{\n+  LaggedFibonacciGenerator::FillJunkData(out, static_cast<size_t>(size), disc_offset,\n+                                          m_disc_id, m_disc_num);\n+}\n+\n+void WbfsFileReader::ReadPartitionInfo()\n+{\n+  std::unique_ptr<VolumeDisc> volume = CreateDisc(CopyReader());\n+  if (!volume)\n+    return;\n+\n+  for (const Partition& partition : volume->GetPartitions())\n+  {\n+    const auto& ticket = volume->GetTicket(partition);\n+    const std::array<u8, 16> title_key = ticket.GetTitleKey();\n+\n+    u8 data_info[8];\n+    if (!Read(partition.offset + 0x2B8, 8, data_info))\n+      continue;\n+\n+    PartitionEntry entry;\n+    entry.data_offset = partition.offset + (static_cast<u64>(Common::swap32(data_info)) << 2);\n+    entry.data_size = static_cast<u64>(Common::swap32(data_info + 4)) << 2;\n+    entry.key = title_key;\n+    m_partitions.push_back(entry);\n+  }\n+}\n+\n+const WbfsFileReader::PartitionEntry* WbfsFileReader::FindPartition(u64 disc_offset) const\n+{\n+  for (const auto& p : m_partitions)\n+  {\n+    if (disc_offset >= p.data_offset && disc_offset < p.data_offset + p.data_size)\n+      return &p;\n+  }\n+  return nullptr;\n+}\n+\n+const WbfsFileReader::PartitionEntry*\n+WbfsFileReader::FindPartitionByDataOffset(u64 partition_data_offset) const\n+{\n+  for (const auto& p : m_partitions)\n+  {\n+    if (p.data_offset == partition_data_offset)\n+      return &p;\n+  }\n+  return nullptr;\n+}\n+\n+bool WbfsFileReader::SupportsReadWiiDecrypted(u64 offset, u64 size,\n+                                               u64 partition_data_offset) const\n+{\n+  return m_has_nkit_header && FindPartitionByDataOffset(partition_data_offset) != nullptr;\n+}\n+\n+bool WbfsFileReader::ReadWiiDecrypted(u64 offset, u64 size, u8* out_ptr,\n+                                       u64 partition_data_offset)\n+{\n+  const PartitionEntry* pe = FindPartitionByDataOffset(partition_data_offset);\n+  if (!pe)\n+    return false;\n+\n+  while (size > 0)\n+  {\n+    const u64 block_in_partition = offset / VolumeWii::BLOCK_DATA_SIZE;\n+    const u64 offset_in_block = offset % VolumeWii::BLOCK_DATA_SIZE;\n+    const u64 bytes_in_block = VolumeWii::BLOCK_DATA_SIZE - offset_in_block;\n+    const u64 read_size = std::min(bytes_in_block, size);\n+\n+    const u64 disc_offset =\n+        partition_data_offset + block_in_partition * VolumeWii::BLOCK_TOTAL_SIZE;\n+    const u64 wbfs_block = disc_offset >> m_header.wbfs_sector_shift;\n+\n+    if (wbfs_block < m_blocks_per_disc && m_wlba_table[wbfs_block] != 0)\n+    {\n+      // Stored sector: read encrypted data and decrypt\n+      u8 encrypted[VolumeWii::BLOCK_TOTAL_SIZE];\n+      u64 available;\n+      auto& file = SeekToCluster(disc_offset, &available);\n+      if (available < VolumeWii::BLOCK_TOTAL_SIZE || !file.Read(encrypted, VolumeWii::BLOCK_TOTAL_SIZE))\n+        return false;\n+      auto aes_ctx = Common::AES::CreateContextDecrypt(pe->key.data());\n+      u8 decrypted[VolumeWii::BLOCK_DATA_SIZE];\n+      VolumeWii::DecryptBlockData(encrypted, decrypted, aes_ctx.get());\n+      std::memcpy(out_ptr, decrypted + offset_in_block, static_cast<size_t>(read_size));', 'path': 'Source/Core/DiscIO/WbfsBlob.cpp', 'position': 234, 'original_position': 234, 'commit_id': '81f336974c3eb2f93c05073734d2d7dc16309a6a', 'user': {'login': 'thethiny', 'id': 6018214, 'node_id': 'MDQ6VXNlcjYwMTgyMTQ=', 'avatar_url': 'https://avatars.githubusercontent.com/u/6018214?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/thethiny', 'html_url': 'https://github.com/thethiny', 'followers_url': 'https://api.github.com/users/thethiny/followers', 'following_url': 'https://api.github.com/users/thethiny/following{/other_user}', 'gists_url': 'https://api.github.com/users/thethiny/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/thethiny/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/thethiny/subscriptions', 'organizations_url': 'https://api.github.com/users/thethiny/orgs', 'repos_url': 'https://api.github.com/users/thethiny/repos', 'events_url': 'https://api.github.com/users/thethiny/events{/privacy}', 'received_events_url': 'https://api.github.com/users/thethiny/received_events', 'type': 'User', 'user_view_type': 'public', 'site_admin': False}, 'body': 'We seem to be disagreeing about encryption vs decryption, in my testing and understanding the behavior here indicates the data is encrypted since it comes from `BlobReader` which has the raw data. This is similar to the points we had above.', 'created_at': '2026-07-18T04:05:37Z', 'updated_at': '2026-07-18T04:05:37Z', 'html_url': 'https://github.com/dolphin-emu/dolphin/pull/14731#discussion_r3607550881', 'pull_request_url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/14731', 'author_association': 'NONE', '_links': {'self': {'href': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/comments/3607550881'}, 'html': {'href': 'https://github.com/dolphin-emu/dolphin/pull/14731#discussion_r3607550881'}, 'pull_request': {'href': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/14731'}}, 'original_commit_id': '81f336974c3eb2f93c05073734d2d7dc16309a6a', 'reactions': {'url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/comments/3607550881/reactions', 'total_count': 0, '+1': 0, '-1': 0, 'laugh': 0, 'hooray': 0, 'confused': 0, 'heart': 0, 'rocket': 0, 'eyes': 0}, 'in_reply_to_id': 3607361519}], 'type': 'gh_pull_request_review'}
2026-07-18T04:01:13.582644	{'source': 'ghhookparser', 'repo': 'dolphin-emu/dolphin', 'author': 'thethiny', 'action': 'submitted', 'pr_id': 14731, 'pr_title': 'Convert To WBFS Support', 'state': 'commented', 'url': 'https://github.com/dolphin-emu/dolphin/pull/14731#pullrequestreview-4727605771', 'comments': [{'id': 3607543613, 'node_id': 'PRRC_kwDOALCn2M7XBr89', 'url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/comments/3607543613', 'pull_request_review_id': 4727605771, 'diff_hunk': '@@ -186,7 +430,362 @@ std::unique_ptr<WbfsFileReader> WbfsFileReader::Create(File::DirectIOFile file,\n   if (!reader->IsGood())\n     reader.reset();\n \n+  if (reader && reader->m_has_nkit_header)\n+    reader->ReadPartitionInfo();\n+\n   return reader;\n }\n \n+// Converts any disc image to WBFS with an NKit v2 header for lossless round-trips.\n+// Strips disc-level junk and partition-level junk (encrypted sectors whose decrypted\n+// content is zero or LFG padding), records a junk bitmap for reconstruction.\n+// See: https://github.com/dolphin-emu/dolphin/pull/14731\n+bool ConvertToWBFS(BlobReader* infile, const std::string& infile_path,\n+                   const std::string& outfile_path, const CompressCB& callback)\n+{\n+  ASSERT(infile->GetDataSizeType() == DataSizeType::Accurate);\n+\n+  File::DirectIOFile outfile(outfile_path, File::AccessMode::Write);\n+  if (!outfile.IsOpen())\n+  {\n+    PanicAlertFmtT(\n+        "Failed to open the output file \\"{0}\\".\\n"\n+        "Check that you have permissions to write the target folder and that the media can "\n+        "be written.",\n+        outfile_path);\n+    return false;\n+  }\n+\n+  const u64 disc_size = infile->GetDataSize();\n+\n+  // These match the values used by standard WBFS tools (wwt, WBFS Manager)\n+  static constexpr u8 hd_sector_shift = 9;\n+  static constexpr u8 wbfs_sector_shift = 21;\n+  static constexpr u64 hd_sector_size = 1ull << hd_sector_shift;\n+  static constexpr u64 wbfs_sector_size = 1ull << wbfs_sector_shift;\n+\n+  const u64 blocks_per_disc = (disc_size + wbfs_sector_size - 1) / wbfs_sector_size;\n+  const u64 disc_info_size =\n+      Common::AlignUp(WII_DISC_HEADER_SIZE + blocks_per_disc * sizeof(u16), hd_sector_size);\n+\n+  // Read disc header (first 256 bytes contain disc_id, disc_num, title, etc.)\n+  std::vector<u8> disc_header(WII_DISC_HEADER_SIZE, 0);\n+  if (!infile->Read(0, WII_DISC_HEADER_SIZE, disc_header.data()))\n+  {\n+    PanicAlertFmtT("Failed to read from the input file \\"{0}\\".", infile_path);\n+    return false;\n+  }\n+\n+  // Use Volume for partition info and decryption (per PR#14731 review)\n+  struct PartitionInfo\n+  {\n+    u64 data_offset;\n+    u64 data_size;\n+    std::unique_ptr<Common::AES::Context> aes_ctx;\n+  };\n+  std::vector<PartitionInfo> partitions;\n+\n+  std::unique_ptr<VolumeDisc> volume = CreateDisc(infile_path);\n+  if (volume)\n+  {\n+    for (const Partition& partition : volume->GetPartitions())\n+    {\n+      const auto& ticket = volume->GetTicket(partition);\n+      const std::array<u8, 16> title_key = ticket.GetTitleKey();\n+\n+      u8 data_info[8];\n+      if (!infile->Read(partition.offset + 0x2B8, 8, data_info))\n+        continue;\n+\n+      PartitionInfo info;\n+      info.data_offset = partition.offset + (static_cast<u64>(Common::swap32(data_info)) << 2);\n+      info.data_size = static_cast<u64>(Common::swap32(data_info + 4)) << 2;\n+      info.aes_ctx = Common::AES::CreateContextDecrypt(title_key.data());\n+      partitions.push_back(std::move(info));\n+    }\n+  }\n+\n+  // NKit v2 junk bitmap: 1 bit per block, MSB-first, always sized for dual-layer\n+  const u64 junk_bits_blocks = (DL_DVD_SIZE + wbfs_sector_size - 1) / wbfs_sector_size;\n+  const u64 junk_bits_bytes = (junk_bits_blocks + 7) / 8;\n+  std::vector<u8> junk_bits(junk_bits_bytes, 0);\n+\n+  // Scan disc: classify each block as used/zero/junk, compute hashes\n+  std::vector<u8> sector_buf(wbfs_sector_size, 0);\n+  std::vector<bool> sector_used(blocks_per_disc, false);\n+  u16 used_count = 0;\n+\n+  // NKit v2 stores four hash digests for verification\n+  auto sha1_ctx = Common::SHA1::CreateContext();\n+  u32 crc = Common::StartCRC32();\n+  mbedtls_md5_context md5_ctx{};\n+  mbedtls_md5_init(&md5_ctx);\n+  mbedtls_md5_starts_ret(&md5_ctx);\n+  XXH64_state_t* xxh_state = XXH64_createState();\n+  XXH64_reset(xxh_state, 0);\n+\n+  for (u64 i = 0; i < blocks_per_disc; i++)\n+  {\n+    if (i % 100 == 0)\n+    {\n+      const bool was_cancelled =\n+          !callback(Common::GetStringT("Scanning"), static_cast<float>(i) /\n+                                                        static_cast<float>(blocks_per_disc) * 0.5f);\n+      if (was_cancelled)\n+      {\n+        XXH64_freeState(xxh_state);\n+        outfile.Close();\n+        File::Delete(outfile_path);\n+        return false;\n+      }\n+    }\n+\n+    const u64 offset = i * wbfs_sector_size;\n+    const u64 sz = std::min(wbfs_sector_size, disc_size - offset);\n+\n+    std::fill(sector_buf.begin(), sector_buf.end(), 0);\n+    if (!infile->Read(offset, sz, sector_buf.data()))\n+    {\n+      PanicAlertFmtT("Failed to read from the input file \\"{0}\\".", infile_path);\n+      XXH64_freeState(xxh_state);\n+      outfile.Close();\n+      File::Delete(outfile_path);\n+      return false;\n+    }\n+\n+    // Update all four hashes with the full disc data\n+    sha1_ctx->Update(sector_buf.data(), static_cast<size_t>(sz));\n+    crc = Common::UpdateCRC32(crc, sector_buf.data(), static_cast<size_t>(sz));\n+    mbedtls_md5_update_ret(&md5_ctx, sector_buf.data(), static_cast<size_t>(sz));\n+    XXH64_update(xxh_state, sector_buf.data(), static_cast<size_t>(sz));\n+\n+    const bool is_zero = std::ranges::all_of(sector_buf, [](u8 b) { return b == 0; });\n+    if (is_zero)\n+      continue;\n+\n+    // Check if the block matches disc-level LFG junk pattern\n+    if (LaggedFibonacciGenerator::IsJunkBlock(sector_buf.data(), static_cast<size_t>(sz),\n+                                               offset, disc_header.data(), disc_header[6]))\n+    {\n+      junk_bits[i / 8] |= static_cast<u8>(1 << (7 - (i & 7)));\n+      continue;\n+    }\n+\n+    // Check partition-level junk: the entire block must fall within a single partition.\n+    if (!partitions.empty())\n+    {\n+      const u32 start_sector = static_cast<u32>(offset / VolumeWii::BLOCK_TOTAL_SIZE);\n+      const u32 end_sector =\n+          static_cast<u32>((offset + sz) / VolumeWii::BLOCK_TOTAL_SIZE);\n+      const PartitionInfo* pi = nullptr;\n+      for (const auto& p : partitions)\n+      {\n+        const u32 p_start = static_cast<u32>(p.data_offset / VolumeWii::BLOCK_TOTAL_SIZE);\n+        const u32 p_end =\n+            static_cast<u32>((p.data_offset + p.data_size) / VolumeWii::BLOCK_TOTAL_SIZE);\n+        if (start_sector >= p_start && end_sector <= p_end)\n+        {\n+          pi = &p;\n+          break;\n+        }\n+      }\n+\n+      if (pi)\n+      {\n+        // All-zero and all-junk are checked separately - mixed blocks are stored.\n+        bool all_zero = true;\n+        bool all_junk = true;\n+        for (u64 sub = 0; sub < sz; sub += VolumeWii::BLOCK_TOTAL_SIZE)\n+        {\n+          const u64 abs = offset + sub;\n+          const u8* encrypted_sector = sector_buf.data() + sub;\n+          u8 decrypted[VolumeWii::BLOCK_DATA_SIZE];\n+          VolumeWii::DecryptBlockData(encrypted_sector, decrypted, pi->aes_ctx.get());', 'path': 'Source/Core/DiscIO/WbfsBlob.cpp', 'position': 491, 'original_position': 491, 'commit_id': '81f336974c3eb2f93c05073734d2d7dc16309a6a', 'user': {'login': 'thethiny', 'id': 6018214, 'node_id': 'MDQ6VXNlcjYwMTgyMTQ=', 'avatar_url': 'https://avatars.githubusercontent.com/u/6018214?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/thethiny', 'html_url': 'https://github.com/thethiny', 'followers_url': 'https://api.github.com/users/thethiny/followers', 'following_url': 'https://api.github.com/users/thethiny/following{/other_user}', 'gists_url': 'https://api.github.com/users/thethiny/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/thethiny/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/thethiny/subscriptions', 'organizations_url': 'https://api.github.com/users/thethiny/orgs', 'repos_url': 'https://api.github.com/users/thethiny/repos', 'events_url': 'https://api.github.com/users/thethiny/events{/privacy}', 'received_events_url': 'https://api.github.com/users/thethiny/received_events', 'type': 'User', 'user_view_type': 'public', 'site_admin': False}, 'body': 'To my knowledge AES encryption by itself is not symmetrical only the key is, so I think this follows the same concept as the above comments?', 'created_at': '2026-07-18T04:01:11Z', 'updated_at': '2026-07-18T04:01:12Z', 'html_url': 'https://github.com/dolphin-emu/dolphin/pull/14731#discussion_r3607543613', 'pull_request_url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/14731', 'author_association': 'NONE', '_links': {'self': {'href': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/comments/3607543613'}, 'html': {'href': 'https://github.com/dolphin-emu/dolphin/pull/14731#discussion_r3607543613'}, 'pull_request': {'href': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/14731'}}, 'original_commit_id': '81f336974c3eb2f93c05073734d2d7dc16309a6a', 'reactions': {'url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/comments/3607543613/reactions', 'total_count': 0, '+1': 0, '-1': 0, 'laugh': 0, 'hooray': 0, 'confused': 0, 'heart': 0, 'rocket': 0, 'eyes': 0}, 'in_reply_to_id': 3607243309}], 'type': 'gh_pull_request_review'}
2026-07-18T03:51:52.360107	{'source': 'ghhookparser', 'repo': 'dolphin-emu/dolphin', 'author': 'thethiny', 'action': 'submitted', 'pr_id': 14731, 'pr_title': 'Convert To WBFS Support', 'state': 'commented', 'url': 'https://github.com/dolphin-emu/dolphin/pull/14731#pullrequestreview-4727581819', 'comments': [{'id': 3607523249, 'node_id': 'PRRC_kwDOALCn2M7XBm-x', 'url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/comments/3607523249', 'pull_request_review_id': 4727581819, 'diff_hunk': '@@ -186,7 +430,362 @@ std::unique_ptr<WbfsFileReader> WbfsFileReader::Create(File::DirectIOFile file,\n   if (!reader->IsGood())\n     reader.reset();\n \n+  if (reader && reader->m_has_nkit_header)\n+    reader->ReadPartitionInfo();\n+\n   return reader;\n }\n \n+// Converts any disc image to WBFS with an NKit v2 header for lossless round-trips.\n+// Strips disc-level junk and partition-level junk (encrypted sectors whose decrypted\n+// content is zero or LFG padding), records a junk bitmap for reconstruction.\n+// See: https://github.com/dolphin-emu/dolphin/pull/14731\n+bool ConvertToWBFS(BlobReader* infile, const std::string& infile_path,\n+                   const std::string& outfile_path, const CompressCB& callback)\n+{\n+  ASSERT(infile->GetDataSizeType() == DataSizeType::Accurate);\n+\n+  File::DirectIOFile outfile(outfile_path, File::AccessMode::Write);\n+  if (!outfile.IsOpen())\n+  {\n+    PanicAlertFmtT(\n+        "Failed to open the output file \\"{0}\\".\\n"\n+        "Check that you have permissions to write the target folder and that the media can "\n+        "be written.",\n+        outfile_path);\n+    return false;\n+  }\n+\n+  const u64 disc_size = infile->GetDataSize();\n+\n+  // These match the values used by standard WBFS tools (wwt, WBFS Manager)\n+  static constexpr u8 hd_sector_shift = 9;\n+  static constexpr u8 wbfs_sector_shift = 21;\n+  static constexpr u64 hd_sector_size = 1ull << hd_sector_shift;\n+  static constexpr u64 wbfs_sector_size = 1ull << wbfs_sector_shift;\n+\n+  const u64 blocks_per_disc = (disc_size + wbfs_sector_size - 1) / wbfs_sector_size;\n+  const u64 disc_info_size =\n+      Common::AlignUp(WII_DISC_HEADER_SIZE + blocks_per_disc * sizeof(u16), hd_sector_size);\n+\n+  // Read disc header (first 256 bytes contain disc_id, disc_num, title, etc.)\n+  std::vector<u8> disc_header(WII_DISC_HEADER_SIZE, 0);\n+  if (!infile->Read(0, WII_DISC_HEADER_SIZE, disc_header.data()))\n+  {\n+    PanicAlertFmtT("Failed to read from the input file \\"{0}\\".", infile_path);\n+    return false;\n+  }\n+\n+  // Use Volume for partition info and decryption (per PR#14731 review)\n+  struct PartitionInfo\n+  {\n+    u64 data_offset;\n+    u64 data_size;\n+    std::unique_ptr<Common::AES::Context> aes_ctx;\n+  };\n+  std::vector<PartitionInfo> partitions;\n+\n+  std::unique_ptr<VolumeDisc> volume = CreateDisc(infile_path);\n+  if (volume)\n+  {\n+    for (const Partition& partition : volume->GetPartitions())\n+    {\n+      const auto& ticket = volume->GetTicket(partition);\n+      const std::array<u8, 16> title_key = ticket.GetTitleKey();\n+\n+      u8 data_info[8];\n+      if (!infile->Read(partition.offset + 0x2B8, 8, data_info))\n+        continue;\n+\n+      PartitionInfo info;\n+      info.data_offset = partition.offset + (static_cast<u64>(Common::swap32(data_info)) << 2);\n+      info.data_size = static_cast<u64>(Common::swap32(data_info + 4)) << 2;\n+      info.aes_ctx = Common::AES::CreateContextDecrypt(title_key.data());\n+      partitions.push_back(std::move(info));\n+    }\n+  }\n+\n+  // NKit v2 junk bitmap: 1 bit per block, MSB-first, always sized for dual-layer\n+  const u64 junk_bits_blocks = (DL_DVD_SIZE + wbfs_sector_size - 1) / wbfs_sector_size;\n+  const u64 junk_bits_bytes = (junk_bits_blocks + 7) / 8;\n+  std::vector<u8> junk_bits(junk_bits_bytes, 0);\n+\n+  // Scan disc: classify each block as used/zero/junk, compute hashes\n+  std::vector<u8> sector_buf(wbfs_sector_size, 0);\n+  std::vector<bool> sector_used(blocks_per_disc, false);\n+  u16 used_count = 0;\n+\n+  // NKit v2 stores four hash digests for verification\n+  auto sha1_ctx = Common::SHA1::CreateContext();\n+  u32 crc = Common::StartCRC32();\n+  mbedtls_md5_context md5_ctx{};\n+  mbedtls_md5_init(&md5_ctx);\n+  mbedtls_md5_starts_ret(&md5_ctx);\n+  XXH64_state_t* xxh_state = XXH64_createState();\n+  XXH64_reset(xxh_state, 0);\n+\n+  for (u64 i = 0; i < blocks_per_disc; i++)\n+  {\n+    if (i % 100 == 0)\n+    {\n+      const bool was_cancelled =\n+          !callback(Common::GetStringT("Scanning"), static_cast<float>(i) /\n+                                                        static_cast<float>(blocks_per_disc) * 0.5f);\n+      if (was_cancelled)\n+      {\n+        XXH64_freeState(xxh_state);\n+        outfile.Close();\n+        File::Delete(outfile_path);\n+        return false;\n+      }\n+    }\n+\n+    const u64 offset = i * wbfs_sector_size;\n+    const u64 sz = std::min(wbfs_sector_size, disc_size - offset);\n+\n+    std::fill(sector_buf.begin(), sector_buf.end(), 0);\n+    if (!infile->Read(offset, sz, sector_buf.data()))\n+    {\n+      PanicAlertFmtT("Failed to read from the input file \\"{0}\\".", infile_path);\n+      XXH64_freeState(xxh_state);\n+      outfile.Close();\n+      File::Delete(outfile_path);\n+      return false;\n+    }\n+\n+    // Update all four hashes with the full disc data\n+    sha1_ctx->Update(sector_buf.data(), static_cast<size_t>(sz));\n+    crc = Common::UpdateCRC32(crc, sector_buf.data(), static_cast<size_t>(sz));\n+    mbedtls_md5_update_ret(&md5_ctx, sector_buf.data(), static_cast<size_t>(sz));\n+    XXH64_update(xxh_state, sector_buf.data(), static_cast<size_t>(sz));\n+\n+    const bool is_zero = std::ranges::all_of(sector_buf, [](u8 b) { return b == 0; });\n+    if (is_zero)\n+      continue;\n+\n+    // Check if the block matches disc-level LFG junk pattern\n+    if (LaggedFibonacciGenerator::IsJunkBlock(sector_buf.data(), static_cast<size_t>(sz),\n+                                               offset, disc_header.data(), disc_header[6]))\n+    {\n+      junk_bits[i / 8] |= static_cast<u8>(1 << (7 - (i & 7)));\n+      continue;\n+    }\n+\n+    // Check partition-level junk: the entire block must fall within a single partition.\n+    if (!partitions.empty())\n+    {\n+      const u32 start_sector = static_cast<u32>(offset / VolumeWii::BLOCK_TOTAL_SIZE);\n+      const u32 end_sector =\n+          static_cast<u32>((offset + sz) / VolumeWii::BLOCK_TOTAL_SIZE);\n+      const PartitionInfo* pi = nullptr;\n+      for (const auto& p : partitions)\n+      {\n+        const u32 p_start = static_cast<u32>(p.data_offset / VolumeWii::BLOCK_TOTAL_SIZE);\n+        const u32 p_end =\n+            static_cast<u32>((p.data_offset + p.data_size) / VolumeWii::BLOCK_TOTAL_SIZE);\n+        if (start_sector >= p_start && end_sector <= p_end)\n+        {\n+          pi = &p;\n+          break;\n+        }\n+      }\n+\n+      if (pi)\n+      {\n+        // All-zero and all-junk are checked separately - mixed blocks are stored.\n+        bool all_zero = true;\n+        bool all_junk = true;\n+        for (u64 sub = 0; sub < sz; sub += VolumeWii::BLOCK_TOTAL_SIZE)\n+        {\n+          const u64 abs = offset + sub;\n+          const u8* encrypted_sector = sector_buf.data() + sub;\n+          u8 decrypted[VolumeWii::BLOCK_DATA_SIZE];', 'path': 'Source/Core/DiscIO/WbfsBlob.cpp', 'position': 490, 'original_position': 490, 'commit_id': '81f336974c3eb2f93c05073734d2d7dc16309a6a', 'user': {'login': 'thethiny', 'id': 6018214, 'node_id': 'MDQ6VXNlcjYwMTgyMTQ=', 'avatar_url': 'https://avatars.githubusercontent.com/u/6018214?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/thethiny', 'html_url': 'https://github.com/thethiny', 'followers_url': 'https://api.github.com/users/thethiny/followers', 'following_url': 'https://api.github.com/users/thethiny/following{/other_user}', 'gists_url': 'https://api.github.com/users/thethiny/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/thethiny/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/thethiny/subscriptions', 'organizations_url': 'https://api.github.com/users/thethiny/orgs', 'repos_url': 'https://api.github.com/users/thethiny/repos', 'events_url': 'https://api.github.com/users/thethiny/events{/privacy}', 'received_events_url': 'https://api.github.com/users/thethiny/received_events', 'type': 'User', 'user_view_type': 'public', 'site_admin': False}, 'body': 'similar to above, and referncing the WIA Blob https://github.com/thethiny/dolphin/blob/81f336974c3eb2f93c05073734d2d7dc16309a6a/Source/Core/DiscIO/WIABlob.cpp#L1404', 'created_at': '2026-07-18T03:51:50Z', 'updated_at': '2026-07-18T03:51:50Z', 'html_url': 'https://github.com/dolphin-emu/dolphin/pull/14731#discussion_r3607523249', 'pull_request_url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/14731', 'author_association': 'NONE', '_links': {'self': {'href': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/comments/3607523249'}, 'html': {'href': 'https://github.com/dolphin-emu/dolphin/pull/14731#discussion_r3607523249'}, 'pull_request': {'href': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/14731'}}, 'original_commit_id': '81f336974c3eb2f93c05073734d2d7dc16309a6a', 'reactions': {'url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/comments/3607523249/reactions', 'total_count': 0, '+1': 0, '-1': 0, 'laugh': 0, 'hooray': 0, 'confused': 0, 'heart': 0, 'rocket': 0, 'eyes': 0}, 'in_reply_to_id': 3607238150}], 'type': 'gh_pull_request_review'}
2026-07-18T03:51:21.636365	{'source': 'ghhookparser', 'repo': 'dolphin-emu/dolphin', 'author': 'phire', 'action': 'submitted', 'pr_id': 14731, 'pr_title': 'Convert To WBFS Support', 'state': 'commented', 'url': 'https://github.com/dolphin-emu/dolphin/pull/14731#pullrequestreview-4727580579', 'comments': [{'id': 3607521800, 'node_id': 'PRRC_kwDOALCn2M7XBmoI', 'url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/comments/3607521800', 'pull_request_review_id': 4727580579, 'diff_hunk': '@@ -186,7 +430,362 @@ std::unique_ptr<WbfsFileReader> WbfsFileReader::Create(File::DirectIOFile file,\n   if (!reader->IsGood())\n     reader.reset();\n \n+  if (reader && reader->m_has_nkit_header)\n+    reader->ReadPartitionInfo();\n+\n   return reader;\n }\n \n+// Converts any disc image to WBFS with an NKit v2 header for lossless round-trips.\n+// Strips disc-level junk and partition-level junk (encrypted sectors whose decrypted\n+// content is zero or LFG padding), records a junk bitmap for reconstruction.\n+// See: https://github.com/dolphin-emu/dolphin/pull/14731\n+bool ConvertToWBFS(BlobReader* infile, const std::string& infile_path,\n+                   const std::string& outfile_path, const CompressCB& callback)\n+{\n+  ASSERT(infile->GetDataSizeType() == DataSizeType::Accurate);\n+\n+  File::DirectIOFile outfile(outfile_path, File::AccessMode::Write);\n+  if (!outfile.IsOpen())\n+  {\n+    PanicAlertFmtT(\n+        "Failed to open the output file \\"{0}\\".\\n"\n+        "Check that you have permissions to write the target folder and that the media can "\n+        "be written.",\n+        outfile_path);\n+    return false;\n+  }\n+\n+  const u64 disc_size = infile->GetDataSize();\n+\n+  // These match the values used by standard WBFS tools (wwt, WBFS Manager)\n+  static constexpr u8 hd_sector_shift = 9;\n+  static constexpr u8 wbfs_sector_shift = 21;\n+  static constexpr u64 hd_sector_size = 1ull << hd_sector_shift;\n+  static constexpr u64 wbfs_sector_size = 1ull << wbfs_sector_shift;\n+\n+  const u64 blocks_per_disc = (disc_size + wbfs_sector_size - 1) / wbfs_sector_size;\n+  const u64 disc_info_size =\n+      Common::AlignUp(WII_DISC_HEADER_SIZE + blocks_per_disc * sizeof(u16), hd_sector_size);\n+\n+  // Read disc header (first 256 bytes contain disc_id, disc_num, title, etc.)\n+  std::vector<u8> disc_header(WII_DISC_HEADER_SIZE, 0);\n+  if (!infile->Read(0, WII_DISC_HEADER_SIZE, disc_header.data()))\n+  {\n+    PanicAlertFmtT("Failed to read from the input file \\"{0}\\".", infile_path);\n+    return false;\n+  }\n+\n+  // Use Volume for partition info and decryption (per PR#14731 review)\n+  struct PartitionInfo\n+  {\n+    u64 data_offset;\n+    u64 data_size;\n+    std::unique_ptr<Common::AES::Context> aes_ctx;\n+  };\n+  std::vector<PartitionInfo> partitions;\n+\n+  std::unique_ptr<VolumeDisc> volume = CreateDisc(infile_path);\n+  if (volume)\n+  {\n+    for (const Partition& partition : volume->GetPartitions())\n+    {\n+      const auto& ticket = volume->GetTicket(partition);\n+      const std::array<u8, 16> title_key = ticket.GetTitleKey();\n+\n+      u8 data_info[8];\n+      if (!infile->Read(partition.offset + 0x2B8, 8, data_info))\n+        continue;\n+\n+      PartitionInfo info;\n+      info.data_offset = partition.offset + (static_cast<u64>(Common::swap32(data_info)) << 2);\n+      info.data_size = static_cast<u64>(Common::swap32(data_info + 4)) << 2;\n+      info.aes_ctx = Common::AES::CreateContextDecrypt(title_key.data());\n+      partitions.push_back(std::move(info));\n+    }\n+  }\n+\n+  // NKit v2 junk bitmap: 1 bit per block, MSB-first, always sized for dual-layer\n+  const u64 junk_bits_blocks = (DL_DVD_SIZE + wbfs_sector_size - 1) / wbfs_sector_size;\n+  const u64 junk_bits_bytes = (junk_bits_blocks + 7) / 8;\n+  std::vector<u8> junk_bits(junk_bits_bytes, 0);\n+\n+  // Scan disc: classify each block as used/zero/junk, compute hashes\n+  std::vector<u8> sector_buf(wbfs_sector_size, 0);\n+  std::vector<bool> sector_used(blocks_per_disc, false);\n+  u16 used_count = 0;\n+\n+  // NKit v2 stores four hash digests for verification\n+  auto sha1_ctx = Common::SHA1::CreateContext();\n+  u32 crc = Common::StartCRC32();\n+  mbedtls_md5_context md5_ctx{};\n+  mbedtls_md5_init(&md5_ctx);\n+  mbedtls_md5_starts_ret(&md5_ctx);\n+  XXH64_state_t* xxh_state = XXH64_createState();\n+  XXH64_reset(xxh_state, 0);\n+\n+  for (u64 i = 0; i < blocks_per_disc; i++)\n+  {\n+    if (i % 100 == 0)\n+    {\n+      const bool was_cancelled =\n+          !callback(Common::GetStringT("Scanning"), static_cast<float>(i) /\n+                                                        static_cast<float>(blocks_per_disc) * 0.5f);\n+      if (was_cancelled)\n+      {\n+        XXH64_freeState(xxh_state);\n+        outfile.Close();\n+        File::Delete(outfile_path);\n+        return false;\n+      }\n+    }\n+\n+    const u64 offset = i * wbfs_sector_size;\n+    const u64 sz = std::min(wbfs_sector_size, disc_size - offset);\n+\n+    std::fill(sector_buf.begin(), sector_buf.end(), 0);\n+    if (!infile->Read(offset, sz, sector_buf.data()))\n+    {\n+      PanicAlertFmtT("Failed to read from the input file \\"{0}\\".", infile_path);\n+      XXH64_freeState(xxh_state);\n+      outfile.Close();\n+      File::Delete(outfile_path);\n+      return false;\n+    }\n+\n+    // Update all four hashes with the full disc data\n+    sha1_ctx->Update(sector_buf.data(), static_cast<size_t>(sz));\n+    crc = Common::UpdateCRC32(crc, sector_buf.data(), static_cast<size_t>(sz));\n+    mbedtls_md5_update_ret(&md5_ctx, sector_buf.data(), static_cast<size_t>(sz));\n+    XXH64_update(xxh_state, sector_buf.data(), static_cast<size_t>(sz));\n+\n+    const bool is_zero = std::ranges::all_of(sector_buf, [](u8 b) { return b == 0; });\n+    if (is_zero)\n+      continue;\n+\n+    // Check if the block matches disc-level LFG junk pattern\n+    if (LaggedFibonacciGenerator::IsJunkBlock(sector_buf.data(), static_cast<size_t>(sz),\n+                                               offset, disc_header.data(), disc_header[6]))\n+    {\n+      junk_bits[i / 8] |= static_cast<u8>(1 << (7 - (i & 7)));\n+      continue;\n+    }', 'path': 'Source/Core/DiscIO/WbfsBlob.cpp', 'position': 460, 'original_position': 460, 'commit_id': '81f336974c3eb2f93c05073734d2d7dc16309a6a', 'user': {'login': 'phire', 'id': 138484, 'node_id': 'MDQ6VXNlcjEzODQ4NA==', 'avatar_url': 'https://avatars.githubusercontent.com/u/138484?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/phire', 'html_url': 'https://github.com/phire', 'followers_url': 'https://api.github.com/users/phire/followers', 'following_url': 'https://api.github.com/users/phire/following{/other_user}', 'gists_url': 'https://api.github.com/users/phire/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/phire/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/phire/subscriptions', 'organizations_url': 'https://api.github.com/users/phire/orgs', 'repos_url': 'https://api.github.com/users/phire/repos', 'events_url': 'https://api.github.com/users/phire/events{/privacy}', 'received_events_url': 'https://api.github.com/users/phire/received_events', 'type': 'User', 'user_view_type': 'public', 'site_admin': False}, 'body': "Yeah... I might be confused about if `Read` returns encrypted or decrypted data. \r\n\r\nI think I'm confusing Volume::Read which returns decrypted, and BlobReader::Read which is meant to return encrypted (at least for Wii discs). \r\n\r\nThough looks like WbfsBlob reader was previously returning decrypted data, which WiiVolume::Read was detecting (somehow) and directly passing thought. ", 'created_at': '2026-07-18T03:51:19Z', 'updated_at': '2026-07-18T03:51:20Z', 'html_url': 'https://github.com/dolphin-emu/dolphin/pull/14731#discussion_r3607521800', 'pull_request_url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/14731', 'author_association': 'MEMBER', '_links': {'self': {'href': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/comments/3607521800'}, 'html': {'href': 'https://github.com/dolphin-emu/dolphin/pull/14731#discussion_r3607521800'}, 'pull_request': {'href': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/14731'}}, 'original_commit_id': '81f336974c3eb2f93c05073734d2d7dc16309a6a', 'reactions': {'url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/comments/3607521800/reactions', 'total_count': 0, '+1': 0, '-1': 0, 'laugh': 0, 'hooray': 0, 'confused': 0, 'heart': 0, 'rocket': 0, 'eyes': 0}, 'in_reply_to_id': 3607206463}], 'type': 'gh_pull_request_review'}
2026-07-18T03:46:46.691390	{'source': 'ghhookparser', 'repo': 'dolphin-emu/dolphin', 'author': 'thethiny', 'action': 'submitted', 'pr_id': 14731, 'pr_title': 'Convert To WBFS Support', 'state': 'commented', 'url': 'https://github.com/dolphin-emu/dolphin/pull/14731#pullrequestreview-4727573120', 'comments': [{'id': 3607514349, 'node_id': 'PRRC_kwDOALCn2M7XBkzt', 'url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/comments/3607514349', 'pull_request_review_id': 4727573120, 'diff_hunk': '@@ -186,7 +430,362 @@ std::unique_ptr<WbfsFileReader> WbfsFileReader::Create(File::DirectIOFile file,\n   if (!reader->IsGood())\n     reader.reset();\n \n+  if (reader && reader->m_has_nkit_header)\n+    reader->ReadPartitionInfo();\n+\n   return reader;\n }\n \n+// Converts any disc image to WBFS with an NKit v2 header for lossless round-trips.\n+// Strips disc-level junk and partition-level junk (encrypted sectors whose decrypted\n+// content is zero or LFG padding), records a junk bitmap for reconstruction.\n+// See: https://github.com/dolphin-emu/dolphin/pull/14731\n+bool ConvertToWBFS(BlobReader* infile, const std::string& infile_path,\n+                   const std::string& outfile_path, const CompressCB& callback)\n+{\n+  ASSERT(infile->GetDataSizeType() == DataSizeType::Accurate);\n+\n+  File::DirectIOFile outfile(outfile_path, File::AccessMode::Write);\n+  if (!outfile.IsOpen())\n+  {\n+    PanicAlertFmtT(\n+        "Failed to open the output file \\"{0}\\".\\n"\n+        "Check that you have permissions to write the target folder and that the media can "\n+        "be written.",\n+        outfile_path);\n+    return false;\n+  }\n+\n+  const u64 disc_size = infile->GetDataSize();\n+\n+  // These match the values used by standard WBFS tools (wwt, WBFS Manager)\n+  static constexpr u8 hd_sector_shift = 9;\n+  static constexpr u8 wbfs_sector_shift = 21;\n+  static constexpr u64 hd_sector_size = 1ull << hd_sector_shift;\n+  static constexpr u64 wbfs_sector_size = 1ull << wbfs_sector_shift;\n+\n+  const u64 blocks_per_disc = (disc_size + wbfs_sector_size - 1) / wbfs_sector_size;\n+  const u64 disc_info_size =\n+      Common::AlignUp(WII_DISC_HEADER_SIZE + blocks_per_disc * sizeof(u16), hd_sector_size);\n+\n+  // Read disc header (first 256 bytes contain disc_id, disc_num, title, etc.)\n+  std::vector<u8> disc_header(WII_DISC_HEADER_SIZE, 0);\n+  if (!infile->Read(0, WII_DISC_HEADER_SIZE, disc_header.data()))\n+  {\n+    PanicAlertFmtT("Failed to read from the input file \\"{0}\\".", infile_path);\n+    return false;\n+  }\n+\n+  // Use Volume for partition info and decryption (per PR#14731 review)\n+  struct PartitionInfo\n+  {\n+    u64 data_offset;\n+    u64 data_size;\n+    std::unique_ptr<Common::AES::Context> aes_ctx;\n+  };\n+  std::vector<PartitionInfo> partitions;\n+\n+  std::unique_ptr<VolumeDisc> volume = CreateDisc(infile_path);\n+  if (volume)\n+  {\n+    for (const Partition& partition : volume->GetPartitions())\n+    {\n+      const auto& ticket = volume->GetTicket(partition);\n+      const std::array<u8, 16> title_key = ticket.GetTitleKey();\n+\n+      u8 data_info[8];\n+      if (!infile->Read(partition.offset + 0x2B8, 8, data_info))\n+        continue;\n+\n+      PartitionInfo info;\n+      info.data_offset = partition.offset + (static_cast<u64>(Common::swap32(data_info)) << 2);\n+      info.data_size = static_cast<u64>(Common::swap32(data_info + 4)) << 2;\n+      info.aes_ctx = Common::AES::CreateContextDecrypt(title_key.data());\n+      partitions.push_back(std::move(info));\n+    }\n+  }\n+\n+  // NKit v2 junk bitmap: 1 bit per block, MSB-first, always sized for dual-layer\n+  const u64 junk_bits_blocks = (DL_DVD_SIZE + wbfs_sector_size - 1) / wbfs_sector_size;\n+  const u64 junk_bits_bytes = (junk_bits_blocks + 7) / 8;\n+  std::vector<u8> junk_bits(junk_bits_bytes, 0);\n+\n+  // Scan disc: classify each block as used/zero/junk, compute hashes\n+  std::vector<u8> sector_buf(wbfs_sector_size, 0);\n+  std::vector<bool> sector_used(blocks_per_disc, false);\n+  u16 used_count = 0;\n+\n+  // NKit v2 stores four hash digests for verification\n+  auto sha1_ctx = Common::SHA1::CreateContext();\n+  u32 crc = Common::StartCRC32();\n+  mbedtls_md5_context md5_ctx{};\n+  mbedtls_md5_init(&md5_ctx);\n+  mbedtls_md5_starts_ret(&md5_ctx);\n+  XXH64_state_t* xxh_state = XXH64_createState();\n+  XXH64_reset(xxh_state, 0);\n+\n+  for (u64 i = 0; i < blocks_per_disc; i++)\n+  {\n+    if (i % 100 == 0)\n+    {\n+      const bool was_cancelled =\n+          !callback(Common::GetStringT("Scanning"), static_cast<float>(i) /\n+                                                        static_cast<float>(blocks_per_disc) * 0.5f);\n+      if (was_cancelled)\n+      {\n+        XXH64_freeState(xxh_state);\n+        outfile.Close();\n+        File::Delete(outfile_path);\n+        return false;\n+      }\n+    }\n+\n+    const u64 offset = i * wbfs_sector_size;\n+    const u64 sz = std::min(wbfs_sector_size, disc_size - offset);\n+\n+    std::fill(sector_buf.begin(), sector_buf.end(), 0);\n+    if (!infile->Read(offset, sz, sector_buf.data()))\n+    {\n+      PanicAlertFmtT("Failed to read from the input file \\"{0}\\".", infile_path);\n+      XXH64_freeState(xxh_state);\n+      outfile.Close();\n+      File::Delete(outfile_path);\n+      return false;\n+    }\n+\n+    // Update all four hashes with the full disc data\n+    sha1_ctx->Update(sector_buf.data(), static_cast<size_t>(sz));\n+    crc = Common::UpdateCRC32(crc, sector_buf.data(), static_cast<size_t>(sz));\n+    mbedtls_md5_update_ret(&md5_ctx, sector_buf.data(), static_cast<size_t>(sz));\n+    XXH64_update(xxh_state, sector_buf.data(), static_cast<size_t>(sz));\n+\n+    const bool is_zero = std::ranges::all_of(sector_buf, [](u8 b) { return b == 0; });\n+    if (is_zero)\n+      continue;\n+\n+    // Check if the block matches disc-level LFG junk pattern\n+    if (LaggedFibonacciGenerator::IsJunkBlock(sector_buf.data(), static_cast<size_t>(sz),\n+                                               offset, disc_header.data(), disc_header[6]))\n+    {\n+      junk_bits[i / 8] |= static_cast<u8>(1 << (7 - (i & 7)));\n+      continue;\n+    }\n+\n+    // Check partition-level junk: the entire block must fall within a single partition.\n+    if (!partitions.empty())\n+    {\n+      const u32 start_sector = static_cast<u32>(offset / VolumeWii::BLOCK_TOTAL_SIZE);\n+      const u32 end_sector =\n+          static_cast<u32>((offset + sz) / VolumeWii::BLOCK_TOTAL_SIZE);\n+      const PartitionInfo* pi = nullptr;\n+      for (const auto& p : partitions)\n+      {\n+        const u32 p_start = static_cast<u32>(p.data_offset / VolumeWii::BLOCK_TOTAL_SIZE);\n+        const u32 p_end =\n+            static_cast<u32>((p.data_offset + p.data_size) / VolumeWii::BLOCK_TOTAL_SIZE);\n+        if (start_sector >= p_start && end_sector <= p_end)\n+        {\n+          pi = &p;\n+          break;\n+        }\n+      }\n+\n+      if (pi)\n+      {\n+        // All-zero and all-junk are checked separately - mixed blocks are stored.\n+        bool all_zero = true;\n+        bool all_junk = true;\n+        for (u64 sub = 0; sub < sz; sub += VolumeWii::BLOCK_TOTAL_SIZE)\n+        {\n+          const u64 abs = offset + sub;\n+          const u8* encrypted_sector = sector_buf.data() + sub;', 'path': 'Source/Core/DiscIO/WbfsBlob.cpp', 'position': 489, 'original_position': 489, 'commit_id': '81f336974c3eb2f93c05073734d2d7dc16309a6a', 'user': {'login': 'thethiny', 'id': 6018214, 'node_id': 'MDQ6VXNlcjYwMTgyMTQ=', 'avatar_url': 'https://avatars.githubusercontent.com/u/6018214?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/thethiny', 'html_url': 'https://github.com/thethiny', 'followers_url': 'https://api.github.com/users/thethiny/followers', 'following_url': 'https://api.github.com/users/thethiny/following{/other_user}', 'gists_url': 'https://api.github.com/users/thethiny/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/thethiny/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/thethiny/subscriptions', 'organizations_url': 'https://api.github.com/users/thethiny/orgs', 'repos_url': 'https://api.github.com/users/thethiny/repos', 'events_url': 'https://api.github.com/users/thethiny/events{/privacy}', 'received_events_url': 'https://api.github.com/users/thethiny/received_events', 'type': 'User', 'user_view_type': 'public', 'site_admin': False}, 'body': 'This is similar to the comment above, this is coming from `BlobReader*` which does not do decryption.', 'created_at': '2026-07-18T03:46:44Z', 'updated_at': '2026-07-18T03:46:45Z', 'html_url': 'https://github.com/dolphin-emu/dolphin/pull/14731#discussion_r3607514349', 'pull_request_url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/14731', 'author_association': 'NONE', '_links': {'self': {'href': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/comments/3607514349'}, 'html': {'href': 'https://github.com/dolphin-emu/dolphin/pull/14731#discussion_r3607514349'}, 'pull_request': {'href': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/14731'}}, 'original_commit_id': '81f336974c3eb2f93c05073734d2d7dc16309a6a', 'reactions': {'url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/comments/3607514349/reactions', 'total_count': 0, '+1': 0, '-1': 0, 'laugh': 0, 'hooray': 0, 'confused': 0, 'heart': 0, 'rocket': 0, 'eyes': 0}, 'in_reply_to_id': 3607236755}], 'type': 'gh_pull_request_review'}

Recent 'gh_push' events

2026-07-18T10:34:55.890029	{'source': 'ghhookparser', 'repo': 'dolphin-emu/dolphin', 'pusher': 'JosJuice', 'before_sha': 'b6d8bc299ee7d03496d624b2e6b9a18d70522435', 'after_sha': '415ec4de182034179143231e84c17dbcdf8be8aa', 'commits': [{'author': {'name': 'tommywaaf', 'email': 'tommywaaf@users.noreply.github.com', 'date': '2026-06-05T12:37:30-04:00', 'username': 'tommywaaf'}, 'distinct': False, 'added': [], 'modified': ['Source/Core/Core/HW/WiimoteReal/IOAndroid.cpp'], 'removed': [], 'message': 'Android: Route DolphinBar Balance Board to the Balance Board slot\n\nWiimoteScannerAndroid::FindAttachedWiimotes() added every device\nconnected through the DolphinBar to the Wii Remote results, with a\nTODO noting that balance boards were not differentiated. As a result,\na Wii Balance Board connected through the DolphinBar was always\nassigned to a Wii Remote slot (Player 1), and games that request a\nBalance Board never detected it.\n\nUse Wiimote::IsBalanceBoard() to route balance boards into the\nbalance_boards results, matching the Linux and Windows scanner\nbackends. Tested on an AYN Thor (Android 13) with a Mayflash\nDolphinBar in Mode 4 running Wii Fit Plus: the board is now detected\nin the Balance Board slot.', 'url': 'https://github.com/dolphin-emu/dolphin/commit/342115806beb93a1f14dd9e40b6839148d70b986', 'hash': '342115806beb93a1f14dd9e40b6839148d70b986'}, {'author': {'name': 'JosJuice', 'email': 'josjuice@gmail.com', 'date': '2026-07-18T12:34:53+02:00', 'username': 'JosJuice'}, 'distinct': True, 'added': [], 'modified': ['Source/Core/Core/HW/WiimoteReal/IOAndroid.cpp'], 'removed': [], 'message': 'Merge pull request #14673 from tommywaaf/android-dolphinbar-balance-board\n\nAndroid: Route DolphinBar Balance Board to the Balance Board slot', 'url': 'https://github.com/dolphin-emu/dolphin/commit/415ec4de182034179143231e84c17dbcdf8be8aa', 'hash': '415ec4de182034179143231e84c17dbcdf8be8aa'}], 'base_ref_name': None, 'ref_name': 'master', 'ref_type': 'heads', 'created': False, 'deleted': False, 'forced': False, 'type': 'gh_push'}
2026-07-15T20:58:04.240863	{'source': 'ghhookparser', 'repo': 'dolphin-emu/dolphin', 'pusher': 'phire', 'before_sha': '81402ca6aa93503be38736b5dd6d8d96fcbfd0d5', 'after_sha': 'b6d8bc299ee7d03496d624b2e6b9a18d70522435', 'commits': [{'author': {'name': 'JosJuice', 'email': 'josjuice@gmail.com', 'date': '2026-07-12T10:05:14+02:00', 'username': 'JosJuice'}, 'distinct': False, 'added': [], 'modified': ['Source/Core/InputCommon/GCAdapter.cpp'], 'removed': [], 'message': "GCAdapter: Deregister callback when scan thread exits\n\nWe were registering the hotplug callback when starting the thread, but\nderegistering it when shutting down GCAdapter as a whole. Because the\nthread can start and stop potentially many times before GCAdapter shuts\ndown, this led to callbacks being registered when we already have\ncallbacks. On Android, this was making Dolphin's Kotlin code for\nregistering the callback throw an IllegalStateException.\n\nTo fix this, deregister the callback when stopping the thread.", 'url': 'https://github.com/dolphin-emu/dolphin/commit/05855a37f4d6b9e98e41e7c50983faa167ae03ac', 'hash': '05855a37f4d6b9e98e41e7c50983faa167ae03ac'}, {'author': {'name': 'Scott Mansell', 'email': 'phiren@gmail.com', 'date': '2026-07-16T08:58:02+12:00', 'username': 'phire'}, 'distinct': True, 'added': [], 'modified': ['Source/Core/InputCommon/GCAdapter.cpp'], 'removed': [], 'message': 'Merge pull request #14726 from JosJuice/gcadapter-deregister-on-thread-end\n\nGCAdapter: Deregister callback when scan thread exits', 'url': 'https://github.com/dolphin-emu/dolphin/commit/b6d8bc299ee7d03496d624b2e6b9a18d70522435', 'hash': 'b6d8bc299ee7d03496d624b2e6b9a18d70522435'}], 'base_ref_name': None, 'ref_name': 'master', 'ref_type': 'heads', 'created': False, 'deleted': False, 'forced': False, 'type': 'gh_push'}
2026-07-15T20:08:15.227032	{'source': 'ghhookparser', 'repo': 'dolphin-emu/dolphin', 'pusher': 'AdmiralCurtiss', 'before_sha': 'fd8391a85241d1b359d662342c5c66f8f4b96d10', 'after_sha': '81402ca6aa93503be38736b5dd6d8d96fcbfd0d5', 'commits': [{'author': {'name': 'Khang', 'email': 'khang06@users.noreply.github.com', 'date': '2026-07-15T02:12:31-04:00', 'username': 'khang06'}, 'distinct': False, 'added': [], 'modified': ['Source/Core/Core/IOS/ES/Formats.cpp', 'Source/Core/Core/IOS/WFS/WFSI.cpp', 'Source/Core/DiscIO/VolumeWad.cpp'], 'removed': [], 'message': 'IOS/ES: Prevent reading TMDs that are too small', 'url': 'https://github.com/dolphin-emu/dolphin/commit/900febec29bcfee8b7a1319ec74d9cb1bfb9d157', 'hash': '900febec29bcfee8b7a1319ec74d9cb1bfb9d157'}, {'author': {'name': 'Admiral H. Curtiss', 'email': 'pikachu025@gmail.com', 'date': '2026-07-15T22:08:12+02:00', 'username': 'AdmiralCurtiss'}, 'distinct': True, 'added': [], 'modified': ['Source/Core/Core/IOS/ES/Formats.cpp', 'Source/Core/Core/IOS/WFS/WFSI.cpp', 'Source/Core/DiscIO/VolumeWad.cpp'], 'removed': [], 'message': 'Merge pull request #14732 from khang06/small-tmd-check\n\nIOS/ES: Prevent reading TMDs that are too small', 'url': 'https://github.com/dolphin-emu/dolphin/commit/81402ca6aa93503be38736b5dd6d8d96fcbfd0d5', 'hash': '81402ca6aa93503be38736b5dd6d8d96fcbfd0d5'}], 'base_ref_name': None, 'ref_name': 'master', 'ref_type': 'heads', 'created': False, 'deleted': False, 'forced': False, 'type': 'gh_push'}
2026-07-15T05:48:32.496949	{'source': 'ghhookparser', 'repo': 'dolphin-emu/dolphin', 'pusher': 'phire', 'before_sha': '566519d13553c054980b8eed390c1f26a1f866fa', 'after_sha': 'fd8391a85241d1b359d662342c5c66f8f4b96d10', 'commits': [{'author': {'name': 'Joshua Vandaële', 'email': 'joshua@vandaele.software', 'date': '2026-01-08T16:40:43+01:00', 'username': 'JoshuaVandaele'}, 'distinct': False, 'added': [], 'modified': ['CMakeLists.txt'], 'removed': [], 'message': 'CCache: Set as opt-in by default', 'url': 'https://github.com/dolphin-emu/dolphin/commit/271a140715081f05989b11ab5e9bc754f87935ff', 'hash': '271a140715081f05989b11ab5e9bc754f87935ff'}, {'author': {'name': 'Scott Mansell', 'email': 'phiren@gmail.com', 'date': '2026-07-15T17:48:30+12:00', 'username': 'phire'}, 'distinct': True, 'added': [], 'modified': ['CMakeLists.txt'], 'removed': [], 'message': 'Merge pull request #14263 from JoshuaVandaele/ccache-toggle\n\nCCache: Set as opt-in by default', 'url': 'https://github.com/dolphin-emu/dolphin/commit/fd8391a85241d1b359d662342c5c66f8f4b96d10', 'hash': 'fd8391a85241d1b359d662342c5c66f8f4b96d10'}], 'base_ref_name': None, 'ref_name': 'master', 'ref_type': 'heads', 'created': False, 'deleted': False, 'forced': False, 'type': 'gh_push'}
2026-07-15T05:46:56.195344	{'source': 'ghhookparser', 'repo': 'dolphin-emu/dolphin', 'pusher': 'phire', 'before_sha': 'ee5eba860d999b2bf7ca1b5011877ab4a78f56d2', 'after_sha': '566519d13553c054980b8eed390c1f26a1f866fa', 'commits': [{'author': {'name': 'Sintendo', 'email': '3380580+Sintendo@users.noreply.github.com', 'date': '2025-12-21T14:37:45+01:00', 'username': 'Sintendo'}, 'distinct': False, 'added': [], 'modified': ['Source/Core/Core/PowerPC/PPCSymbolDB.cpp', 'Source/Core/Core/PowerPC/PPCSymbolDB.h'], 'removed': [], 'message': 'PPCSymbolDB: Avoid double lookup', 'url': 'https://github.com/dolphin-emu/dolphin/commit/56438bde447696f8d5c2aca135d0e75ce88c7b2f', 'hash': '56438bde447696f8d5c2aca135d0e75ce88c7b2f'}, {'author': {'name': 'Scott Mansell', 'email': 'phiren@gmail.com', 'date': '2026-07-15T17:46:54+12:00', 'username': 'phire'}, 'distinct': True, 'added': [], 'modified': ['Source/Core/Core/PowerPC/PPCSymbolDB.cpp', 'Source/Core/Core/PowerPC/PPCSymbolDB.h'], 'removed': [], 'message': 'Merge pull request #14222 from Sintendo/ppcsymboldb-lookup\n\nPPCSymbolDB: Avoid double lookups', 'url': 'https://github.com/dolphin-emu/dolphin/commit/566519d13553c054980b8eed390c1f26a1f866fa', 'hash': '566519d13553c054980b8eed390c1f26a1f866fa'}], 'base_ref_name': None, 'ref_name': 'master', 'ref_type': 'heads', 'created': False, 'deleted': False, 'forced': False, 'type': 'gh_push'}
2026-07-15T05:08:13.994283	{'source': 'ghhookparser', 'repo': 'dolphin-emu/dolphin', 'pusher': 'phire', 'before_sha': '552126a0e6524ac7e0e8f5ec40ca9dbd06291071', 'after_sha': 'ee5eba860d999b2bf7ca1b5011877ab4a78f56d2', 'commits': [{'author': {'name': 'DacoTaco', 'email': 'daco_65@hotmail.com', 'date': '2026-05-13T20:26:47+02:00', 'username': 'DacoTaco'}, 'distinct': False, 'added': [], 'modified': ['Source/Core/Core/Boot/DolReader.cpp'], 'removed': [], 'message': 'fixes: make dolreader validate section addresses and sizes\n\nIOS and IPL reject non-32byte aligned sections', 'url': 'https://github.com/dolphin-emu/dolphin/commit/21d44f32bad3a384396efafc612d74ef6f5eff8e', 'hash': '21d44f32bad3a384396efafc612d74ef6f5eff8e'}, {'author': {'name': 'Scott Mansell', 'email': 'phiren@gmail.com', 'date': '2026-07-15T17:08:11+12:00', 'username': 'phire'}, 'distinct': True, 'added': [], 'modified': ['Source/Core/Core/Boot/DolReader.cpp'], 'removed': [], 'message': 'Merge pull request #14651 from DacoTaco/fixes/dolalignment\n\nfixes: make dolreader validate section addresses and sizes', 'url': 'https://github.com/dolphin-emu/dolphin/commit/ee5eba860d999b2bf7ca1b5011877ab4a78f56d2', 'hash': 'ee5eba860d999b2bf7ca1b5011877ab4a78f56d2'}], 'base_ref_name': None, 'ref_name': 'master', 'ref_type': 'heads', 'created': False, 'deleted': False, 'forced': False, 'type': 'gh_push'}
2026-07-15T05:01:48.407751	{'source': 'ghhookparser', 'repo': 'dolphin-emu/dolphin', 'pusher': 'phire', 'before_sha': '1ab4403c236fa34ce8807c4895f705913217372d', 'after_sha': '552126a0e6524ac7e0e8f5ec40ca9dbd06291071', 'commits': [{'author': {'name': 'JosJuice', 'email': 'josjuice@gmail.com', 'date': '2026-06-07T11:01:04+02:00', 'username': 'JosJuice'}, 'distinct': False, 'added': [], 'modified': ['Data/Sys/GameSettings/ID-gbihf.ini'], 'removed': [], 'message': "GameSettings: Remove SafeTextureCacheColorSamples from gbihf\n\nExtrems said that it's unnecessary because GBIHF doesn't use the GPU.\nVideo output doesn't work in GBIHF in Dolphin regardless of this\nsetting, so I can't actually test it.", 'url': 'https://github.com/dolphin-emu/dolphin/commit/896ecddb7751e0b1efee8d0ddb45d8a2c95aa0d4', 'hash': '896ecddb7751e0b1efee8d0ddb45d8a2c95aa0d4'}, {'author': {'name': 'Scott Mansell', 'email': 'phiren@gmail.com', 'date': '2026-07-15T17:01:46+12:00', 'username': 'phire'}, 'distinct': True, 'added': [], 'modified': ['Data/Sys/GameSettings/ID-gbihf.ini'], 'removed': [], 'message': 'Merge pull request #14675 from JosJuice/game-ini-gbihf-texcache\n\nGameSettings: Remove SafeTextureCacheColorSamples from gbihf', 'url': 'https://github.com/dolphin-emu/dolphin/commit/552126a0e6524ac7e0e8f5ec40ca9dbd06291071', 'hash': '552126a0e6524ac7e0e8f5ec40ca9dbd06291071'}], 'base_ref_name': None, 'ref_name': 'master', 'ref_type': 'heads', 'created': False, 'deleted': False, 'forced': False, 'type': 'gh_push'}
2026-07-15T05:00:30.473308	{'source': 'ghhookparser', 'repo': 'dolphin-emu/dolphin', 'pusher': 'phire', 'before_sha': 'd895ed7d5cb493aa461a1a0aedc683c0c3b70925', 'after_sha': '1ab4403c236fa34ce8807c4895f705913217372d', 'commits': [{'author': {'name': 'Joshua Vandaële', 'email': 'joshua@vandaele.software', 'date': '2026-06-27T09:52:14+02:00', 'username': 'JoshuaVandaele'}, 'distinct': False, 'added': [], 'modified': ['Externals/miniupnpc/CMakeLists.txt'], 'removed': [], 'message': 'Externals/miniupnpc: Disable warnings', 'url': 'https://github.com/dolphin-emu/dolphin/commit/af6c6ffacff3a0d7b2e1b5d1b28322848ed86c01', 'hash': 'af6c6ffacff3a0d7b2e1b5d1b28322848ed86c01'}, {'author': {'name': 'Scott Mansell', 'email': 'phiren@gmail.com', 'date': '2026-07-15T17:00:28+12:00', 'username': 'phire'}, 'distinct': True, 'added': [], 'modified': ['Externals/miniupnpc/CMakeLists.txt'], 'removed': [], 'message': 'Merge pull request #14703 from JoshuaVandaele/miniupnpc-arm64-cross\n\nExternals/miniupnpc: Disable warnings', 'url': 'https://github.com/dolphin-emu/dolphin/commit/1ab4403c236fa34ce8807c4895f705913217372d', 'hash': '1ab4403c236fa34ce8807c4895f705913217372d'}], 'base_ref_name': None, 'ref_name': 'master', 'ref_type': 'heads', 'created': False, 'deleted': False, 'forced': False, 'type': 'gh_push'}
2026-07-15T04:45:46.107013	{'source': 'ghhookparser', 'repo': 'dolphin-emu/dolphin', 'pusher': 'phire', 'before_sha': 'd3b2943807dd0073f7767947466dd73cccfef319', 'after_sha': 'd895ed7d5cb493aa461a1a0aedc683c0c3b70925', 'commits': [{'author': {'name': 'idkwhere1sthisname', 'email': 'comestaix@gmail.com', 'date': '2026-07-11T19:10:20+02:00', 'username': 'idkwhere1sthisname'}, 'distinct': False, 'added': [], 'modified': ['Source/Core/Core/IOS/ES/ES.cpp'], 'removed': [], 'message': 'allow Wii System Transfer and WagonCompat to call ES_SetUID', 'url': 'https://github.com/dolphin-emu/dolphin/commit/8873338b8d59e7b675d31978e42b541fd4431d0a', 'hash': '8873338b8d59e7b675d31978e42b541fd4431d0a'}, {'author': {'name': 'Scott Mansell', 'email': 'phiren@gmail.com', 'date': '2026-07-15T16:45:43+12:00', 'username': 'phire'}, 'distinct': True, 'added': [], 'modified': ['Source/Core/Core/IOS/ES/ES.cpp'], 'removed': [], 'message': 'Merge pull request #14722 from idkwhere1sthisname/master\n\nIOS/ES: allow Wii System Transfer and WagonCompat Transfer Tool to pass SetUID check', 'url': 'https://github.com/dolphin-emu/dolphin/commit/d895ed7d5cb493aa461a1a0aedc683c0c3b70925', 'hash': 'd895ed7d5cb493aa461a1a0aedc683c0c3b70925'}], 'base_ref_name': None, 'ref_name': 'master', 'ref_type': 'heads', 'created': False, 'deleted': False, 'forced': False, 'type': 'gh_push'}
2026-07-14T20:52:11.190076	{'source': 'ghhookparser', 'repo': 'dolphin-emu/dolphin', 'pusher': 'Dentomologist', 'before_sha': '00beaa84a550fe35755910d96182d04e0996450b', 'after_sha': 'd3b2943807dd0073f7767947466dd73cccfef319', 'commits': [{'author': {'name': 'JosJuice', 'email': 'josjuice@gmail.com', 'date': '2026-06-28T11:05:52+02:00', 'username': 'JosJuice'}, 'distinct': False, 'added': [], 'modified': ['Source/Core/DiscIO/DirectoryBlob.cpp'], 'removed': [], 'message': "DiscIO: Add DTK alignment comment in DirectoryBlob\n\nThis requirement came up in the review of e013d95. Instead of just\nremoving the comment like e013d95 did, let's add a more detailed\ncomment.", 'url': 'https://github.com/dolphin-emu/dolphin/commit/baf154de0e1f518cf48e85ef5c1a2e5196d93d74', 'hash': 'baf154de0e1f518cf48e85ef5c1a2e5196d93d74'}, {'author': {'name': 'Dentomologist', 'email': 'dentomologist@gmail.com', 'date': '2026-07-14T13:52:09-07:00', 'username': 'Dentomologist'}, 'distinct': True, 'added': [], 'modified': ['Source/Core/DiscIO/DirectoryBlob.cpp'], 'removed': [], 'message': 'Merge pull request #14705 from JosJuice/directoryblob-dtk-comment\n\nDiscIO: Add DTK alignment comment in DirectoryBlob', 'url': 'https://github.com/dolphin-emu/dolphin/commit/d3b2943807dd0073f7767947466dd73cccfef319', 'hash': 'd3b2943807dd0073f7767947466dd73cccfef319'}], 'base_ref_name': None, 'ref_name': 'master', 'ref_type': 'heads', 'created': False, 'deleted': False, 'forced': False, 'type': 'gh_push'}
2026-07-14T18:58:48.187431	{'source': 'ghhookparser', 'repo': 'dolphin-emu/dolphin', 'pusher': 'Dentomologist', 'before_sha': '37726b610d3e6596b6af505178e6bf074c949b26', 'after_sha': '00beaa84a550fe35755910d96182d04e0996450b', 'commits': [{'author': {'name': 'Joshua Vandaële', 'email': 'joshua@vandaele.software', 'date': '2026-07-14T14:51:38+02:00', 'username': 'JoshuaVandaele'}, 'distinct': False, 'added': [], 'modified': ['Contributing.md'], 'removed': [], 'message': 'Contributing.md: Update C++20 mentions to C++23', 'url': 'https://github.com/dolphin-emu/dolphin/commit/cdb93d0c99444b7d2c2a00b4264aec5aee4676ca', 'hash': 'cdb93d0c99444b7d2c2a00b4264aec5aee4676ca'}, {'author': {'name': 'Dentomologist', 'email': 'dentomologist@gmail.com', 'date': '2026-07-14T11:58:45-07:00', 'username': 'Dentomologist'}, 'distinct': True, 'added': [], 'modified': ['Contributing.md'], 'removed': [], 'message': 'Merge pull request #14730 from JoshuaVandaele/contributing-cxx-standard\n\nContributing.md: Update C++20 mentions to C++23', 'url': 'https://github.com/dolphin-emu/dolphin/commit/00beaa84a550fe35755910d96182d04e0996450b', 'hash': '00beaa84a550fe35755910d96182d04e0996450b'}], 'base_ref_name': None, 'ref_name': 'master', 'ref_type': 'heads', 'created': False, 'deleted': False, 'forced': False, 'type': 'gh_push'}
2026-07-14T17:26:17.479050	{'source': 'ghhookparser', 'repo': 'dolphin-emu/dolphin', 'pusher': 'AdmiralCurtiss', 'before_sha': 'fee15d96ad094f3a91a1b8074f8d1a113d7d55c2', 'after_sha': '37726b610d3e6596b6af505178e6bf074c949b26', 'commits': [{'author': {'name': 'Dentomologist', 'email': 'dentomologist@gmail.com', 'date': '2026-07-09T21:11:43-07:00', 'username': 'Dentomologist'}, 'distinct': False, 'added': [], 'modified': ['Source/Core/DolphinQt/ResourcePackManager.cpp'], 'removed': [], 'message': "ResourcePackManager: Fix crash when removing pack\n\nAvoid accessing destroyed `QTableWidgetItem` by retrieving the desired\npath from the item before it's destroyed.\n\nIn `ResourcePackManager::Remove` pointers to the selected items in `m_table_widget`\nwere saved in the local variable `items` before calling `Uninstall`.\n`Uninstall` called `RepopulateTable` which called\n`m_table_widget->clear()`, destroying the table's descendants.  Upon\nreturning to `Remove` `items` then pointed to some of those destroyed descendants, and\npassing `items[0]` to `GetResourcePackIndex` resulted in a call to\n`item->row()` which was a use-after-free.\n\nFixes https://bugs.dolphin-emu.org/issues/14095.", 'url': 'https://github.com/dolphin-emu/dolphin/commit/37dd6c287eac591b4d97cbfd90d16c2093b68020', 'hash': '37dd6c287eac591b4d97cbfd90d16c2093b68020'}, {'author': {'name': 'Dentomologist', 'email': 'dentomologist@gmail.com', 'date': '2026-07-10T19:51:06-07:00', 'username': 'Dentomologist'}, 'distinct': False, 'added': [], 'modified': ['Source/Core/DolphinQt/ResourcePackManager.cpp'], 'removed': [], 'message': 'ResourcePackManager: Erase Removed pack from list and table\n\nErase a removed pack from ResourcePack::<anonymous namespace>::packs\ninstead of only deleting the pack file from the disk.\n\nThis causes the repopulated table to actually display that the pack has\nbeen removed (which previously only happened after restarting Dolphin or\nhitting `Refresh`), and also removes the pack from the `Packs.ini` file.', 'url': 'https://github.com/dolphin-emu/dolphin/commit/a18fd2d21b82f33c5ec603d0a76e136db0e30a4c', 'hash': 'a18fd2d21b82f33c5ec603d0a76e136db0e30a4c'}, {'author': {'name': 'Admiral H. Curtiss', 'email': 'pikachu025@gmail.com', 'date': '2026-07-14T19:26:15+02:00', 'username': 'AdmiralCurtiss'}, 'distinct': True, 'added': [], 'modified': ['Source/Core/DolphinQt/ResourcePackManager.cpp'], 'removed': [], 'message': 'Merge pull request #14723 from Dentomologist/resource_pack_manager_fix_crash_when_removing_pack\n\nResourcePackManager: Fix crash when removing pack and properly update list', 'url': 'https://github.com/dolphin-emu/dolphin/commit/37726b610d3e6596b6af505178e6bf074c949b26', 'hash': '37726b610d3e6596b6af505178e6bf074c949b26'}], 'base_ref_name': None, 'ref_name': 'master', 'ref_type': 'heads', 'created': False, 'deleted': False, 'forced': False, 'type': 'gh_push'}
2026-07-14T17:15:01.711897	{'source': 'ghhookparser', 'repo': 'dolphin-emu/dolphin', 'pusher': 'AdmiralCurtiss', 'before_sha': '1b67ed71f40cf7b7afcac68bda08a52d8d44f164', 'after_sha': 'fee15d96ad094f3a91a1b8074f8d1a113d7d55c2', 'commits': [{'author': {'name': 'Craig Carnell', 'email': '1188869+cscd98@users.noreply.github.com', 'date': '2026-07-11T10:53:59+01:00', 'username': 'cscd98'}, 'distinct': False, 'added': [], 'modified': ['Source/Core/Core/Boot/Boot.cpp'], 'removed': [], 'message': 'm3u: normalize line endings except win32', 'url': 'https://github.com/dolphin-emu/dolphin/commit/4b55c26cdbfbdc6434dbbbf78fbe89650262e5b5', 'hash': '4b55c26cdbfbdc6434dbbbf78fbe89650262e5b5'}, {'author': {'name': 'Admiral H. Curtiss', 'email': 'pikachu025@gmail.com', 'date': '2026-07-14T19:14:59+02:00', 'username': 'AdmiralCurtiss'}, 'distinct': True, 'added': [], 'modified': ['Source/Core/Core/Boot/Boot.cpp'], 'removed': [], 'message': 'Merge pull request #14719 from cscd98/m3u-fix\n\nm3u: normalize line endings except win32', 'url': 'https://github.com/dolphin-emu/dolphin/commit/fee15d96ad094f3a91a1b8074f8d1a113d7d55c2', 'hash': 'fee15d96ad094f3a91a1b8074f8d1a113d7d55c2'}], 'base_ref_name': None, 'ref_name': 'master', 'ref_type': 'heads', 'created': False, 'deleted': False, 'forced': False, 'type': 'gh_push'}
2026-07-14T16:49:18.571111	{'source': 'ghhookparser', 'repo': 'dolphin-emu/dolphin', 'pusher': 'JosJuice', 'before_sha': '19729879cbf85e3c24363c2af443cacfcc80df43', 'after_sha': '1b67ed71f40cf7b7afcac68bda08a52d8d44f164', 'commits': [{'author': {'name': 'Windsurf7', 'email': 'mountainlake951@gmail.com', 'date': '2026-02-13T04:13:21+03:00', 'username': 'Windsurf7'}, 'distinct': False, 'added': ['Data/Sys/GameSettings/RSVE8P.ini'], 'modified': [], 'removed': [], 'message': 'GameINI: Add codes to Sonic Unleashed\n\nThis PR provides 60 FPS code additions to Sonic Unleashed.\n\nNTSC-U:\n* Added 60 FPS code, coming from the Dolphin wiki.\n* Followed my code naming convention for Sega games.', 'url': 'https://github.com/dolphin-emu/dolphin/commit/b92e98b16c0177c33c6b39e899575225c19bfd36', 'hash': 'b92e98b16c0177c33c6b39e899575225c19bfd36'}, {'author': {'name': 'JosJuice', 'email': 'josjuice@gmail.com', 'date': '2026-07-14T18:49:16+02:00', 'username': 'JosJuice'}, 'distinct': True, 'added': ['Data/Sys/GameSettings/RSVE8P.ini'], 'modified': [], 'removed': [], 'message': 'Merge pull request #14357 from Windsurf7/sonicunleashed-gameini\n\nGameINI: Add codes to Sonic Unleashed', 'url': 'https://github.com/dolphin-emu/dolphin/commit/1b67ed71f40cf7b7afcac68bda08a52d8d44f164', 'hash': '1b67ed71f40cf7b7afcac68bda08a52d8d44f164'}], 'base_ref_name': None, 'ref_name': 'master', 'ref_type': 'heads', 'created': False, 'deleted': False, 'forced': False, 'type': 'gh_push'}
2026-07-14T16:38:40.793323	{'source': 'ghhookparser', 'repo': 'dolphin-emu/dolphin', 'pusher': 'JosJuice', 'before_sha': '09fbe2a93000127d56dde527179e1b41ba804099', 'after_sha': '19729879cbf85e3c24363c2af443cacfcc80df43', 'commits': [{'author': {'name': 'Tom Pratt', 'email': 'tom.pratt@outlook.com', 'date': '2026-05-11T07:33:16-07:00', 'username': 'tom-pratt'}, 'distinct': False, 'added': [], 'modified': ['Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/netplay/ui/NetplayScreen.kt', 'Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/netplay/ui/NetplaySetupScreen.kt', 'Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/ui/theme/DolphinTheme.kt'], 'removed': [], 'message': 'Scaffold / Appbar composable\n\nCustom composable that switched between compact and medium size app bar depending on a combination of orientation and screen size. (Small app bar when horizontal on small devices, medium app bar otherwise. Medium app bar supports collapse on scroll.', 'url': 'https://github.com/dolphin-emu/dolphin/commit/009a87de59951bc4a4484d379f77cf9ed64e04d2', 'hash': '009a87de59951bc4a4484d379f77cf9ed64e04d2'}, {'author': {'name': 'JosJuice', 'email': 'josjuice@gmail.com', 'date': '2026-07-14T18:38:38+02:00', 'username': 'JosJuice'}, 'distinct': True, 'added': [], 'modified': ['Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/netplay/ui/NetplayScreen.kt', 'Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/netplay/ui/NetplaySetupScreen.kt', 'Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/ui/theme/DolphinTheme.kt'], 'removed': [], 'message': 'Merge pull request #14711 from tom-pratt/landscape-netplay-screens\n\nAndroid: Netplay layout update for landscape navigation', 'url': 'https://github.com/dolphin-emu/dolphin/commit/19729879cbf85e3c24363c2af443cacfcc80df43', 'hash': '19729879cbf85e3c24363c2af443cacfcc80df43'}], 'base_ref_name': None, 'ref_name': 'master', 'ref_type': 'heads', 'created': False, 'deleted': False, 'forced': False, 'type': 'gh_push'}
2026-07-14T08:24:26.820990	{'source': 'ghhookparser', 'repo': 'dolphin-emu/dolphin', 'pusher': 'phire', 'before_sha': 'cdaf67c6ce4b5a23c3dd759a439d2bf434396791', 'after_sha': '09fbe2a93000127d56dde527179e1b41ba804099', 'commits': [{'author': {'name': 'Joshua Vandaële', 'email': 'joshua@vandaele.software', 'date': '2026-07-13T02:26:16+02:00', 'username': 'JoshuaVandaele'}, 'distinct': False, 'added': [], 'modified': ['Source/Core/VideoCommon/PerformanceMetrics.h'], 'removed': [], 'message': 'PerformanceMetrics: Fix compiling using clang&libstdc++\n\nWhen using clang and libstdc++, compiling fails with these errors:\n\n```\nFAILED: [code=1] Source/Core/VideoCommon/CMakeFiles/videocommon.dir/PerformanceMetrics.cpp.o\n/usr/sbin/ccache /usr/sbin/clang++ -DAUTOUPDATE=1 -DDATA_DIR=\\"/usr/local/share/dolphin-emu/\\" -DHAS_OPENGL -DHAS_VULKAN -DHAVE_CPPIPC -DHAVE_LIBSYSTEMD -DIMGUI_USER_CONFIG=\\"imgui_user_config.h\\" -DLZMA_API_STATIC -DOFF -DPUGIXML_NO_EXCEPTIONS -DRC_CLIENT_SUPPORTS_HASH -DSFML_STATIC -DSPNG_STATIC -DTINYGLTF_NOEXCEPTION -DTINYGLTF_NO_EXTERNAL_IMAGE -DTINYGLTF_USE_CPP14 -DUSE_ANALYTICS=1 -DUSE_MEMORYWATCHER=1 -DUSE_PIPES=1 -DUSE_RETRO_ACHIEVEMENTS -DZSTD_MULTITHREAD -D_ARCH_64=1 -D_DEFAULT_SOURCE -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE -D_M_X86_64=1 -D__LIBUSB__ -D__STDC_CONSTANT_MACROS -D__STDC_LIMIT_MACROS -I/dolphin-local/Source/Core -I/dolphin-local/Externals/picojson -I/dolphin-local/build/release/x64/Source/Core -I/dolphin-local/Externals/enet/enet/include -I/dolphin-local/Externals/fmt/fmt/include -I/dolphin-local/Externals/mbedtls/include -I/dolphin-local/Externals/minizip-ng/minizip-ng -I/dolphin-local/Externals/liblzma/api -I/dolphin-local/Externals/zstd/zstd/build/cmake/../../lib -I/dolphin-local/Externals/libiconv/include -I/dolphin-local/build/release/x64/Externals/libiconv/lib -I/dolphin-local/Externals/libiconv/libcharset/include -I/dolphin-local/build/release/x64/Externals/libiconv/libcharset -I/dolphin-local/Externals/SFML/SFML/include -I/dolphin-local/Externals/bzip2/bzip2 -I/dolphin-local/Externals/expr/include -I/dolphin-local/Externals/hidapi/hidapi-src/hidapi -I/dolphin-local/Externals/pugixml/pugixml/src -I/dolphin-local/Externals/glslang/glslang/glslang/.. -I/dolphin-local/build/release/x64/include -I/dolphin-local/Externals/rcheevos -I/dolphin-local/Externals/libspng/libspng/spng -I/dolphin-local/Externals/xxhash/xxHash -I/dolphin-local/Externals/imgui -I/dolphin-local/Externals/imgui/imgui -I/dolphin-local/Externals/implot/implot -I/dolphin-local/Externals/glslang/glslang/SPIRV/.. -I/dolphin-local/Externals/tinygltf -isystem /dolphin-local/Externals/libusb/libusb/libusb -isystem /dolphin-local/Externals/glslang/glslang -isystem /dolphin-local/Externals/glslang/glslang/Public -isystem /dolphin-local/Externals/glslang -Qunused-arguments -fcolor-diagnostics -O3 -DNDEBUG -std=c++23 -msse2 -fdiagnostics-color -fno-strict-aliasing -fno-exceptions -fvisibility-inlines-hidden -fvisibility=hidden -fomit-frame-pointer -Wall -Wtype-limits -Wsign-compare -Wignored-qualifiers -Wuninitialized -Wshadow -Wshadow-field-in-constructor -Winit-self -Wmissing-declarations-Wmissing-variable-declarations -Werror=format -Wno-trigraphs -MD -MT Source/Core/VideoCommon/CMakeFiles/videocommon.dir/PerformanceMetrics.cpp.o -MF Source/Core/VideoCommon/CMakeFiles/videocommon.dir/PerformanceMetrics.cpp.o.d -o Source/Core/VideoCommon/CMakeFiles/videocommon.dir/PerformanceMetrics.cpp.o -c /dolphin-local/Source/Core/VideoCommon/PerformanceMetrics.cpp\nIn file included from /dolphin-local/Source/Core/VideoCommon/PerformanceMetrics.cpp:4:\n/dolphin-local/Source/Core/VideoCommon/PerformanceMetrics.h:69:51: error: no matching constructor for initialization of \'std::atomic<FrameBufferSize>\'\n   69 |   std::atomic<FrameBufferSize> m_frame_buffer_size{};\n      |                                                   ^~\n/usr/bin/../lib64/gcc/x86_64-pc-linux-gnu/16/../../../../include/c++/16/atomic:237:17: note: candidate constructor not viable: constraints not satisfied\n  237 |       constexpr atomic() noexcept(is_nothrow_default_constructible_v<_Tp>)\n      |                 ^\n/usr/bin/../lib64/gcc/x86_64-pc-linux-gnu/16/../../../../include/c++/16/atomic:238:11: note: because \'is_default_constructible_v<PerformanceMetrics::FrameBufferSize>\' evaluated to false\n  238 |         requires is_default_constructible_v<_Tp>\n      |                  ^\n/usr/bin/../lib64/gcc/x86_64-pc-linux-gnu/16/../../../../include/c++/16/atomic:246:7: note: candidate constructor not viable: requires 1 argument, but 0 were provided\n  246 |       atomic(const atomic&) = delete;\n      |       ^      ~~~~~~~~~~~~~\n/usr/bin/../lib64/gcc/x86_64-pc-linux-gnu/16/../../../../include/c++/16/atomic:252:17: note: candidate constructor not viable: requires single argument \'__i\', but no arguments were provided\n  252 |       constexpr atomic(_Tp __i) noexcept : _M_i(__i)\n      |                 ^      ~~~~~~~\n1 error generated.\n```\n\nThis was tested and occurs on both Arch and Alpine Linux.', 'url': 'https://github.com/dolphin-emu/dolphin/commit/55761d9e6deca298a6f97941f03ffa56dc36bec3', 'hash': '55761d9e6deca298a6f97941f03ffa56dc36bec3'}, {'author': {'name': 'Scott Mansell', 'email': 'phiren@gmail.com', 'date': '2026-07-14T20:24:24+12:00', 'username': 'phire'}, 'distinct': True, 'added': [], 'modified': ['Source/Core/VideoCommon/PerformanceMetrics.h'], 'removed': [], 'message': 'Merge pull request #14729 from JoshuaVandaele/fix-clang-libstdcpp\n\nPerformanceMetrics: Fix compiling using clang&libstdc++', 'url': 'https://github.com/dolphin-emu/dolphin/commit/09fbe2a93000127d56dde527179e1b41ba804099', 'hash': '09fbe2a93000127d56dde527179e1b41ba804099'}], 'base_ref_name': None, 'ref_name': 'master', 'ref_type': 'heads', 'created': False, 'deleted': False, 'forced': False, 'type': 'gh_push'}
2026-07-13T06:47:22.066551	{'source': 'ghhookparser', 'repo': 'dolphin-emu/dolphin', 'pusher': 'Dentomologist', 'before_sha': 'd6d25b5302073dd4292a2286c753c4b344aec2da', 'after_sha': 'cdaf67c6ce4b5a23c3dd759a439d2bf434396791', 'commits': [{'author': {'name': 'Dentomologist', 'email': 'dentomologist@gmail.com', 'date': '2026-05-05T14:22:22-07:00', 'username': 'Dentomologist'}, 'distinct': False, 'added': [], 'modified': ['Source/Core/DolphinQt/Main.cpp'], 'removed': [], 'message': "Windows: Fix command line output not displaying when using Git Bash\n\nCheck if Dolphin already has a handle for stdout or stderr before trying\nto attach to the console of the parent process.\n\nPreviously, running Dolphin via Git Bash with options like `--help` or\n`--version` wouldn't produce any output. This was the result of the fix\n(1ce75ce21706a8dd9662e77ac9d09de1976f4733) for\nhttps://bugs.dolphin-emu.org/issues/11042, before which output did work\nfor `Git Bash` but didn't for `Command Prompt` or `PowerShell`.", 'url': 'https://github.com/dolphin-emu/dolphin/commit/1a62cdca0e587a31eeae5494d22223976f7dbead', 'hash': '1a62cdca0e587a31eeae5494d22223976f7dbead'}, {'author': {'name': 'Dentomologist', 'email': 'dentomologist@gmail.com', 'date': '2026-07-12T23:47:20-07:00', 'username': 'Dentomologist'}, 'distinct': True, 'added': [], 'modified': ['Source/Core/DolphinQt/Main.cpp'], 'removed': [], 'message': 'Merge pull request #14643 from Dentomologist/windows_git_bash_fix_command_line_output\n\nWindows: Fix command line output not displaying when using Git Bash', 'url': 'https://github.com/dolphin-emu/dolphin/commit/cdaf67c6ce4b5a23c3dd759a439d2bf434396791', 'hash': 'cdaf67c6ce4b5a23c3dd759a439d2bf434396791'}], 'base_ref_name': None, 'ref_name': 'master', 'ref_type': 'heads', 'created': False, 'deleted': False, 'forced': False, 'type': 'gh_push'}
2026-07-13T06:28:30.424484	{'source': 'ghhookparser', 'repo': 'dolphin-emu/dolphin', 'pusher': 'Dentomologist', 'before_sha': '990b4212338375b37a6ab9d480af5f3f9e408243', 'after_sha': 'd6d25b5302073dd4292a2286c753c4b344aec2da', 'commits': [{'author': {'name': 'Windsurf7', 'email': 'mountainlake951@gmail.com', 'date': '2026-02-13T03:51:11+03:00', 'username': 'Windsurf7'}, 'distinct': False, 'added': [], 'modified': ['Data/Sys/GameSettings/R7E.ini'], 'removed': [], 'message': "GameINI: Add codes to NiGHTS Journey of Dreams\n\nThis PR provides 60 FPS code additions to NiGHTS: Journey of Dreams.\n\nNTSC-U/PAL/NTSC-J:\n* Added 60 FPS code, coming from the Dolphin wiki.\n* Followed my code naming convention for Sega games.\n* The wiki says that the code is for NTSC-U but it's actually region free. It's been confirmed via testing.\n* The wiki also says that a certain part in the final level softlocks, but that's actually not true and can be bypassed. An explanation has been included with the code.", 'url': 'https://github.com/dolphin-emu/dolphin/commit/b40047fb6e914a862101da2abeb9e827309cb014', 'hash': 'b40047fb6e914a862101da2abeb9e827309cb014'}, {'author': {'name': 'Dentomologist', 'email': 'dentomologist@gmail.com', 'date': '2026-07-12T23:28:28-07:00', 'username': 'Dentomologist'}, 'distinct': True, 'added': [], 'modified': ['Data/Sys/GameSettings/R7E.ini'], 'removed': [], 'message': 'Merge pull request #14351 from Windsurf7/nightsjod-gameini\n\nGameINI: Add codes to NiGHTS Journey of Dreams', 'url': 'https://github.com/dolphin-emu/dolphin/commit/d6d25b5302073dd4292a2286c753c4b344aec2da', 'hash': 'd6d25b5302073dd4292a2286c753c4b344aec2da'}], 'base_ref_name': None, 'ref_name': 'master', 'ref_type': 'heads', 'created': False, 'deleted': False, 'forced': False, 'type': 'gh_push'}
2026-07-13T05:00:54.394660	{'source': 'ghhookparser', 'repo': 'dolphin-emu/dolphin', 'pusher': 'OatmealDome', 'before_sha': 'f544fbc0aed5b21777003c25c21c85ba846b2093', 'after_sha': '990b4212338375b37a6ab9d480af5f3f9e408243', 'commits': [{'author': {'name': 'Simonx22', 'email': 'simon@oatmealdome.me', 'date': '2026-07-12T10:17:29-04:00', 'username': 'Simonx22'}, 'distinct': False, 'added': [], 'modified': ['Source/Android/app/build.gradle.kts', 'Source/Android/benchmark/build.gradle.kts', 'Source/Android/gradle.properties', 'Source/Android/gradle/libs.versions.toml', 'Source/Android/gradle/wrapper/gradle-wrapper.jar', 'Source/Android/gradle/wrapper/gradle-wrapper.properties', 'Source/Android/gradlew', 'Source/Android/gradlew.bat', 'Source/Android/settings.gradle.kts', 'Source/Core/Core/HW/GCMemcard/GCMemcardUtils.cpp'], 'removed': [], 'message': 'Android: Update dependencies and build tools\n\nUpdate Android dependencies and build tools to their latest available versions.\n\nRename the GameCube save magic constant to avoid a collision with the NDK 30 ARM64 signal context header.', 'url': 'https://github.com/dolphin-emu/dolphin/commit/aeb3fec03aa31fbd14420c10653b27999feffc7d', 'hash': 'aeb3fec03aa31fbd14420c10653b27999feffc7d'}, {'author': {'name': 'OatmealDome', 'email': 'OatmealDome@users.noreply.github.com', 'date': '2026-07-13T01:00:52-04:00', 'username': 'OatmealDome'}, 'distinct': True, 'added': [], 'modified': ['Source/Android/app/build.gradle.kts', 'Source/Android/benchmark/build.gradle.kts', 'Source/Android/gradle.properties', 'Source/Android/gradle/libs.versions.toml', 'Source/Android/gradle/wrapper/gradle-wrapper.jar', 'Source/Android/gradle/wrapper/gradle-wrapper.properties', 'Source/Android/gradlew', 'Source/Android/gradlew.bat', 'Source/Android/settings.gradle.kts', 'Source/Core/Core/HW/GCMemcard/GCMemcardUtils.cpp'], 'removed': [], 'message': 'Merge pull request #14728 from Simonx22/android/api37-ndk30-dependency-updates\n\nAndroid: Update dependencies and build tools', 'url': 'https://github.com/dolphin-emu/dolphin/commit/990b4212338375b37a6ab9d480af5f3f9e408243', 'hash': '990b4212338375b37a6ab9d480af5f3f9e408243'}], 'base_ref_name': None, 'ref_name': 'master', 'ref_type': 'heads', 'created': False, 'deleted': False, 'forced': False, 'type': 'gh_push'}
2026-07-13T05:00:46.084422	{'source': 'ghhookparser', 'repo': 'dolphin-emu/dolphin', 'pusher': 'OatmealDome', 'before_sha': 'b947a11380d02b30592c81ff78c49023e399f681', 'after_sha': 'f544fbc0aed5b21777003c25c21c85ba846b2093', 'commits': [{'author': {'name': 'Simonx22', 'email': 'simon@oatmealdome.me', 'date': '2026-04-30T16:28:38-04:00', 'username': 'Simonx22'}, 'distinct': False, 'added': ['Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/utils/ContentHandler.kt'], 'modified': [], 'removed': ['Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/utils/ContentHandler.java'], 'message': 'Android: Convert ContentHandler to Kotlin and fix warnings', 'url': 'https://github.com/dolphin-emu/dolphin/commit/c93af1d3f94deed81cf288f73c3cfd90aae8e500', 'hash': 'c93af1d3f94deed81cf288f73c3cfd90aae8e500'}, {'author': {'name': 'OatmealDome', 'email': 'OatmealDome@users.noreply.github.com', 'date': '2026-07-13T01:00:44-04:00', 'username': 'OatmealDome'}, 'distinct': True, 'added': ['Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/utils/ContentHandler.kt'], 'modified': [], 'removed': ['Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/utils/ContentHandler.java'], 'message': 'Merge pull request #14630 from Simonx22/android/convert-contenthandler-to-kotlin\n\nAndroid: Convert ContentHandler to Kotlin and fix warnings', 'url': 'https://github.com/dolphin-emu/dolphin/commit/f544fbc0aed5b21777003c25c21c85ba846b2093', 'hash': 'f544fbc0aed5b21777003c25c21c85ba846b2093'}], 'base_ref_name': None, 'ref_name': 'master', 'ref_type': 'heads', 'created': False, 'deleted': False, 'forced': False, 'type': 'gh_push'}
2026-07-13T00:20:47.491777	{'source': 'ghhookparser', 'repo': 'dolphin-emu/dolphin', 'pusher': 'Dentomologist', 'before_sha': 'fc9fd6952a62c4fe48acc00333ce360cb47b57c7', 'after_sha': 'b947a11380d02b30592c81ff78c49023e399f681', 'commits': [{'author': {'name': 'Windsurf7', 'email': 'mountainlake951@gmail.com', 'date': '2026-02-13T04:10:37+03:00', 'username': 'Windsurf7'}, 'distinct': False, 'added': ['Data/Sys/GameSettings/RENE8P.ini', 'Data/Sys/GameSettings/RSRE8P.ini'], 'modified': ['Data/Sys/GameSettings/RSR.ini'], 'removed': [], 'message': 'GameINI: Add codes to Sonic Storybook games\n\nThis PR provides 60 FPS code additions to Sonic and the Secret Rings & Sonic and the Black Knight.\n\nAll regions:\n* Formatting fixes.\n\nNTSC-U/PAL:\n* Added 60 FPS code, coming from the Dolphin wiki.\n* Followed my code naming convention for Sega games.', 'url': 'https://github.com/dolphin-emu/dolphin/commit/a0f514cf60d574a95041d7f58779899b0cf28588', 'hash': 'a0f514cf60d574a95041d7f58779899b0cf28588'}, {'author': {'name': 'Dentomologist', 'email': 'dentomologist@gmail.com', 'date': '2026-07-12T17:20:45-07:00', 'username': 'Dentomologist'}, 'distinct': True, 'added': ['Data/Sys/GameSettings/RENE8P.ini', 'Data/Sys/GameSettings/RSRE8P.ini'], 'modified': ['Data/Sys/GameSettings/RSR.ini'], 'removed': [], 'message': 'Merge pull request #14356 from Windsurf7/sonicstorybook-gameini\n\nGameINI: Add codes to Sonic Storybook games', 'url': 'https://github.com/dolphin-emu/dolphin/commit/b947a11380d02b30592c81ff78c49023e399f681', 'hash': 'b947a11380d02b30592c81ff78c49023e399f681'}], 'base_ref_name': None, 'ref_name': 'master', 'ref_type': 'heads', 'created': False, 'deleted': False, 'forced': False, 'type': 'gh_push'}
2026-07-11T23:34:47.140343	{'source': 'ghhookparser', 'repo': 'dolphin-emu/dolphin', 'pusher': 'phire', 'before_sha': '6de526c684ee6dd8b6fc3447dae858ae480ccbb5', 'after_sha': 'fc9fd6952a62c4fe48acc00333ce360cb47b57c7', 'commits': [{'author': {'name': 'cristian64', 'email': 'cristian64@gmail.com', 'date': '2026-03-27T11:30:52Z', 'username': 'cristian64'}, 'distinct': False, 'added': [], 'modified': ['Source/Core/DiscIO/Volume.h', 'Source/Core/DiscIO/VolumeDisc.cpp', 'Source/Core/DiscIO/VolumeDisc.h', 'Source/Core/DiscIO/VolumeWad.h'], 'removed': [], 'message': 'Core: Add `Volume::GetSimulatedMemorySize()`.\n\nThe data structure of the `bi2.bin` file in which the simulated memory\nsize is set:\n\n> **13.2  Disk header Information**\n>\n> this is loaded to the Address in `0x800000f4` when a disc is initialized by the IPL\n>\n> |  offset  | end | size | Description           |\n> | :------: | --- | :--: | --------------------- |\n> | `0x0000` |     |   4  | Debug-monitor Size    |\n> | `0x0004` |     |   4  | Simulated Memory Size |\n> | `0x0008` |     |   4  | Argument offset       |\n> | `0x000c` |     |   4  | Debug flag            |\n> | `0x0010` |     |   4  | Track Location        |\n> | `0x0014` |     |   4  | Track size            |\n> | `0x0018` |     |   4  | Countrycode           |\n> | `0x001c` |     |   4  | ?                     |\n\nSee https://hitmen.c02.at/files/yagcd/yagcd/chap13.html#sec13.2.\n\nMost GameCube games set the value to `24 MiB`, which matches the\nphysical memory size. Most Wii games set the value to `0 MiB` (unset).\nThe debug build of _Mario Kart: Double Dash!!_ is one game that sets the\nvalue to `48 MiB`.', 'url': 'https://github.com/dolphin-emu/dolphin/commit/24ad5628717df1184fcbac027cd27618891afc40', 'hash': '24ad5628717df1184fcbac027cd27618891afc40'}, {'author': {'name': 'cristian64', 'email': 'cristian64@gmail.com', 'date': '2026-03-27T11:48:18Z', 'username': 'cristian64'}, 'distinct': False, 'added': [], 'modified': ['Source/Core/Core/ConfigManager.cpp', 'Source/Core/Core/ConfigManager.h'], 'removed': [], 'message': 'Core: Add `SConfig::GetSimulatedMemorySize()`.\n\nThis makes the simulated memory size of the running game accessible via\nthe `SConfig` singleton.', 'url': 'https://github.com/dolphin-emu/dolphin/commit/ebcbb79f70a25fa75cbd30da39a65eac8dd9eddd', 'hash': 'ebcbb79f70a25fa75cbd30da39a65eac8dd9eddd'}, {'author': {'name': 'cristian64', 'email': 'cristian64@gmail.com', 'date': '2026-06-29T22:29:37+01:00', 'username': 'cristian64'}, 'distinct': False, 'added': [], 'modified': ['Source/Core/Core/DolphinAnalytics.cpp'], 'removed': [], 'message': 'DolphinAnalytics: Add game quirk for game simulated memory size.\n\nThis is the 32-bit unsigned integer that is seen at offset `0x04` in the\n`bi2.bin` file.\n\nThe intent is to study what games define values that departure from the\nnorm. Common values are 0 MiB (Wii games) and 24 MiB (GameCube games),\nwith some debug and demo builds featuring 48 MiB (e.g. the debug build\nof _Mario Kart: Double Dash!!_).', 'url': 'https://github.com/dolphin-emu/dolphin/commit/03b1f2148b080adc9ed15ecc40e3948404388b61', 'hash': '03b1f2148b080adc9ed15ecc40e3948404388b61'}, {'author': {'name': 'cristian64', 'email': 'cristian64@gmail.com', 'date': '2026-04-03T10:58:54+01:00', 'username': 'cristian64'}, 'distinct': False, 'added': [], 'modified': ['Source/Core/Core/FifoPlayer/FifoDataFile.cpp', 'Source/Core/Core/HW/Memmap.cpp', 'Source/Core/Core/HW/Memmap.h', 'Source/Core/Core/IOS/IOS.cpp', 'Source/Core/Core/System.cpp', 'Source/Core/Core/System.h', 'Source/UnitTests/Core/PowerPC/PageTableHostMappingTest.cpp'], 'removed': [], 'message': 'Core: Adjust emulated memory size automatically.\n\nDolphin now uses the simulated memory size defined in `bi2.bin` to\nadjust the memory size in the emulated console automatically.\n\nIf **Enable Emulated Memory Size Override** has been enabled by the\nuser, the fixed memory size specified for **MEM1** and **MEM2** are\nstill used as they were before.\n\nMost retail games do not define the simulated memory size (Wii or\nTriforce games), or define it to a value that matches the default 24 MiB\n(GameCube games), so, in the general case, there is no behavior change.\nOne game that sets the simulated memory to a non-default value is the\ndebug build of _Mario Kart: Double Dash!!_, where the value is set to\n48 MiB.\n\nThis enhancement is focused mainly to the modding community. Prior to\nthese changes, modded games with extended memory requirements would\nfail to launch in Dolphin [with no indication of what the problem is] if\nthe user failed to set the emulated memory override to the correct\nvalue. Now, modding tools can specify the simulated memory size in the\n`bi2.bin` file to produce extended games that _just work_ in Dolphin,\nwithout cumbersome instructions that can be overlooked by the user.', 'url': 'https://github.com/dolphin-emu/dolphin/commit/0cab1731d61ecb87c7bc388dbd176a4150afbbe3', 'hash': '0cab1731d61ecb87c7bc388dbd176a4150afbbe3'}, {'author': {'name': 'cristian64', 'email': 'cristian64@gmail.com', 'date': '2026-05-30T13:09:58+01:00', 'username': 'cristian64'}, 'distinct': False, 'added': [], 'modified': ['Source/Core/DolphinQt/Settings/AdvancedPane.cpp'], 'removed': [], 'message': 'DolphinQt: Update tool tip for Enable Emulated Memory Size Override.', 'url': 'https://github.com/dolphin-emu/dolphin/commit/594e5d2b56e441760888d56b2d7633520f7770f5', 'hash': '594e5d2b56e441760888d56b2d7633520f7770f5'}, {'author': {'name': 'cristian64', 'email': 'cristian64@gmail.com', 'date': '2026-05-30T13:12:24+01:00', 'username': 'cristian64'}, 'distinct': False, 'added': [], 'modified': ['Source/Android/app/src/main/res/values/strings.xml'], 'removed': [], 'message': 'Android: Update description for Enable Emulated Memory Size Override.', 'url': 'https://github.com/dolphin-emu/dolphin/commit/f9ef6c2151d48ef9b5dbe9ee1c2278e5d60b5ed9', 'hash': 'f9ef6c2151d48ef9b5dbe9ee1c2278e5d60b5ed9'}, {'author': {'name': 'Scott Mansell', 'email': 'phiren@gmail.com', 'date': '2026-07-12T11:34:44+12:00', 'username': 'phire'}, 'distinct': True, 'added': [], 'modified': ['Source/Android/app/src/main/res/values/strings.xml', 'Source/Core/Core/ConfigManager.cpp', 'Source/Core/Core/ConfigManager.h', 'Source/Core/Core/DolphinAnalytics.cpp', 'Source/Core/Core/FifoPlayer/FifoDataFile.cpp', 'Source/Core/Core/HW/Memmap.cpp', 'Source/Core/Core/HW/Memmap.h', 'Source/Core/Core/IOS/IOS.cpp', 'Source/Core/Core/System.cpp', 'Source/Core/Core/System.h', 'Source/Core/DiscIO/Volume.h', 'Source/Core/DiscIO/VolumeDisc.cpp', 'Source/Core/DiscIO/VolumeDisc.h', 'Source/Core/DiscIO/VolumeWad.h', 'Source/Core/DolphinQt/Settings/AdvancedPane.cpp', 'Source/UnitTests/Core/PowerPC/PageTableHostMappingTest.cpp'], 'removed': [], 'message': 'Merge pull request #14665 from cristian64/simulated_memory_size\n\nCore: Adjust emulated memory size automatically.', 'url': 'https://github.com/dolphin-emu/dolphin/commit/fc9fd6952a62c4fe48acc00333ce360cb47b57c7', 'hash': 'fc9fd6952a62c4fe48acc00333ce360cb47b57c7'}], 'base_ref_name': None, 'ref_name': 'master', 'ref_type': 'heads', 'created': False, 'deleted': False, 'forced': False, 'type': 'gh_push'}
2026-07-10T23:23:27.658898	{'source': 'ghhookparser', 'repo': 'dolphin-emu/www', 'pusher': 'OatmealDome', 'before_sha': '397c65711c41caf6cc5037f18c9c984843b95505', 'after_sha': '9d68a88212c67f7d075898f9bc887c09dc3d88fa', 'commits': [{'author': {'name': 'Joshua Vandaële', 'email': 'joshua@vandaele.software', 'date': '2026-07-11T00:42:18+02:00', 'username': 'JoshuaVandaele'}, 'distinct': False, 'added': [], 'modified': ['dolweb/downloads/migrations/0005_release_create_from_betas.py'], 'removed': [], 'message': 'migrations: Fix initial setup', 'url': 'https://github.com/dolphin-emu/www/commit/c90f26255826768daa125d7c81adb03b827829d1', 'hash': 'c90f26255826768daa125d7c81adb03b827829d1'}, {'author': {'name': 'OatmealDome', 'email': 'OatmealDome@users.noreply.github.com', 'date': '2026-07-10T19:23:25-04:00', 'username': 'OatmealDome'}, 'distinct': True, 'added': [], 'modified': ['dolweb/downloads/migrations/0005_release_create_from_betas.py'], 'removed': [], 'message': 'Merge pull request #194 from JoshuaVandaele/migrate-fix\n\nmigrations: Fix initial setup', 'url': 'https://github.com/dolphin-emu/www/commit/9d68a88212c67f7d075898f9bc887c09dc3d88fa', 'hash': '9d68a88212c67f7d075898f9bc887c09dc3d88fa'}], 'base_ref_name': None, 'ref_name': 'stable', 'ref_type': 'heads', 'created': False, 'deleted': False, 'forced': False, 'type': 'gh_push'}
2026-07-10T05:00:35.502864	{'source': 'ghhookparser', 'repo': 'dolphin-emu/sadm', 'pusher': 'OatmealDome', 'before_sha': '49b6a7388c001efe5aa605daf56e965c8840528a', 'after_sha': 'ee02b392c52c0c2a6f2aeba4f56cc65a68fe386a', 'commits': [{'author': {'name': 'OatmealDome', 'email': 'julian@oatmealdome.me', 'date': '2026-07-10T00:35:36-04:00', 'username': 'OatmealDome'}, 'distinct': True, 'added': [], 'modified': ['flake.lock'], 'removed': [], 'message': "flake.lock: Update\n\nFlake lock file updates:\n\n• Updated input 'nixpkgs':\n    'github:NixOS/nixpkgs/7e495b747b51f95ae15e74377c5ce1fe69c1765f?narHash=sha256-B35lpsqnSZwn1Lmz06BpwF7atPgFmUgw1l8KAV3zpVQ%3D' (2026-04-13)\n  → 'github:NixOS/nixpkgs/b6018f87da91d19d0ab4cf979885689b469cdd41?narHash=sha256-twXPFqFsrrY5r28Zh7Homgcp2gUMBgQ6WDS98Q/3xFI%3D' (2026-06-30)\n• Updated input 'pyproject-build-systems':\n    'github:pyproject-nix/build-system-pkgs/b6e74f433b02fa4b8a7965ee24680f4867e2926f?narHash=sha256-ZoTdqZP03DcdoyxvpFHCAek4bkPUTUPUF3oCCgc3dP4%3D' (2026-03-18)\n  → 'github:pyproject-nix/build-system-pkgs/430680a19bc85a3bda55f12e4cc1a1aadcf2e478?narHash=sha256-6gmEVe69%2BKlRkZD4PEEV5xAlB9CB0Y9TiuEgQjDrKTQ%3D' (2026-06-22)\n• Updated input 'pyproject-build-systems/uv2nix':\n    'github:pyproject-nix/uv2nix/27b135ea72ab1637fc5845a61c101ea66d6636d6?narHash=sha256-knv2C6tIk5ysix%2B9TxWIenPvpB20kFjQ1CH6SJMBNsU%3D' (2026-03-12)\n  → 'github:pyproject-nix/uv2nix/14aa44100859a44144878fe079f8089d3fa4dc4e?narHash=sha256-PQfvfKWaBvCysdHFUO5GewwvwIqI/WL6OcrJhDSUdbc%3D' (2026-06-18)\n• Updated input 'pyproject-nix':\n    'github:pyproject-nix/pyproject.nix/29dc4e9960d2b7f122b52b155e0e8f87cd5c5c08?narHash=sha256-mtIBTmVKzyoFYoAGdd8Cd7iswFna9YQVyjObZLXPO64%3D' (2026-04-13)\n  → 'github:pyproject-nix/pyproject.nix/7af23cfe91064865ecf2e835da28b45b3c6f49fd?narHash=sha256-SvXJcAemihifkTn4BGvyE5K1FJX9bl4U8DQ5pqKvD0s%3D' (2026-07-01)\n• Updated input 'rust-overlay':\n    'github:oxalica/rust-overlay/4d6fee71fea68418a48992409b47f1183d0dd111?narHash=sha256-5TD8MYqLMcJi9yV/9jq2dVUPtnu/lKZPD61esQCgvqs%3D' (2026-04-15)\n  → 'github:oxalica/rust-overlay/e8e9d70b96113fd49ccde6c3e08fb260b6ef5dd6?narHash=sha256-zSX553aXiIKJHWzUF6nrDKgeNRlfNK/SdyNYSbs2nkM%3D' (2026-07-09)\n• Updated input 'uv2nix':\n    'github:pyproject-nix/uv2nix/8e11806ae309345b0b92c4dfaf127c8536b56b7c?narHash=sha256-vk66a21DVT2WLjm/PiroInlE/gmeh%2BnotdXiZ1mbq/c%3D' (2026-04-14)\n  → 'github:pyproject-nix/uv2nix/83995ef5e4ece3c9c704aa645bbff439e15a0ac3?narHash=sha256-Z/Ss9rWw9QYcRK%2BQqkmty7PB1pIik5XGbrtit%2Bad2qs%3D' (2026-07-08)", 'url': 'https://github.com/dolphin-emu/sadm/commit/a5cd9daedf8326801bed667f92a540db65986580', 'hash': 'a5cd9daedf8326801bed667f92a540db65986580'}, {'author': {'name': 'OatmealDome', 'email': 'julian@oatmealdome.me', 'date': '2026-07-10T00:48:42-04:00', 'username': 'OatmealDome'}, 'distinct': True, 'added': [], 'modified': ['machines/altair/default.nix'], 'removed': [], 'message': 'machines/altair: Permit use of Docker 28.5.2\nThis should go away after upgrading to NixOS 26.05.', 'url': 'https://github.com/dolphin-emu/sadm/commit/34cd8320cf92325a687ac0163a621dc3e29496b3', 'hash': '34cd8320cf92325a687ac0163a621dc3e29496b3'}, {'author': {'name': 'OatmealDome', 'email': 'julian@oatmealdome.me', 'date': '2026-07-10T00:50:07-04:00', 'username': 'OatmealDome'}, 'distinct': True, 'added': [], 'modified': ['roles/bug-tracker/default.nix'], 'removed': [], 'message': 'bug-tracker: Use built-in blocklist for AI training bots', 'url': 'https://github.com/dolphin-emu/sadm/commit/825f683dc50a45339db67475736bb7544ef07fa0', 'hash': '825f683dc50a45339db67475736bb7544ef07fa0'}, {'author': {'name': 'OatmealDome', 'email': 'julian@oatmealdome.me', 'date': '2026-07-10T00:56:21-04:00', 'username': 'OatmealDome'}, 'distinct': True, 'added': [], 'modified': ['roles/bug-tracker/default.nix'], 'removed': [], 'message': 'bug-tracker: Remove problematic rules on login and register pages', 'url': 'https://github.com/dolphin-emu/sadm/commit/ee02b392c52c0c2a6f2aeba4f56cc65a68fe386a', 'hash': 'ee02b392c52c0c2a6f2aeba4f56cc65a68fe386a'}], 'base_ref_name': None, 'ref_name': 'master', 'ref_type': 'heads', 'created': False, 'deleted': False, 'forced': False, 'type': 'gh_push'}

Recent 'internal_log' events

2026-07-18T23:46:09.549628	{'source': 'logging', 'level': 'INFO', 'pathname': '/nix/store/m89a38mxx677zd2j3gqq91c40d1i7dc6-central-env/lib/python3.13/site-packages/central/github/authz.py', 'lineno': 30, 'msg': 'New GH %s: %s', 'args': "('dolphin-emu/core-developers', 'lioncash,Pokechu22,degasus,Helios747,iwubcode,spycrab,linkmauve,skidau,AdmiralCurtiss,Tilka,leoetlino,Parlane,JosJuice,Dentomologist,OatmealDome,phire,CrossVR,delroth,hrydgard,jordan-woyak')", 'type': 'internal_log'}
2026-07-18T23:46:09.277118	{'source': 'logging', 'level': 'INFO', 'pathname': '/nix/store/m89a38mxx677zd2j3gqq91c40d1i7dc6-central-env/lib/python3.13/site-packages/central/github/authz.py', 'lineno': 21, 'msg': 'Refreshing list of trusted users (from %s/%s)', 'args': "('dolphin-emu', 'core-developers')", 'type': 'internal_log'}
2026-07-18T23:45:27.895462	{'source': 'logging', 'level': 'INFO', 'pathname': '/nix/store/m89a38mxx677zd2j3gqq91c40d1i7dc6-central-env/lib/python3.13/site-packages/central/github/authz.py', 'lineno': 30, 'msg': 'New GH %s: %s', 'args': "('dolphin-emu/trusted-developers', 'EmptyChaos,unknownbrackets,CelestialAmber,Ebola16,Geotale,krnlyng,neobrain,CookiePLMonster,degasus,Stevoisiak,LillyJadeKatrin,iwubcode,kamiyo,Filoppi,hthh,rukai,Linkinworm,Parlane,Starsam80,meffij,phire,delroth,vladfi1,zackhow,malleoz,adamdmoss,NanoByte011,randomstuff,lioncash,mrgreywater,cristian64,Ziek,mimimi085181,deReeperJosh,bentley,jezze,orbea,ligfx,tygyh,magumagu,mathieui,skidau,kayru,endrift,jjdelvalle,Tilka,shonumi,Sintendo,Phatcat,TryTwo,marcan,JosJuice,zopieux,Buddybenj,OatmealDome,JoshuaVandaele,Techjar,Simonx22,JMC47,ColinDTaylor,CasualPokePlayer,Lobsterzelda,hrydgard,spxtr,archshift,corwin-mcknight,ShimmerGlass,aroulin,K0bin,LPFaint99,OrN,aldelaro5,skylersaleh,Helios747,CrystalGamma,nickbeth,tom-pratt,spycrab,magcius,RachelBryk,SuperSamus,AdmiralCurtiss,mmastrac,PatrickFerry,gwicks,BhaaLseN,leoetlino,rlnilsen,cscd98,riking,glennricster,Dentomologist,FioraAeterna,jloehr,comex,Linktothepast,galop1n,mandar1jn,RisingFog,moncefmechri,dreamsyntax,jordan-woyak,hdcmeta,MayImilae,Orphis,hackbar,Pokechu22,crediar,Gamer64ytb,booto,linkmauve,Tinob,Zopolis4,nullgemm,Alcaro,smurf3tte,yourWaifu,LAGonauta,sepalani,mitaclaw,JordanTheToaster,noahpistilli,DacoTaco,CrossVR,TellowKrinkle,Hydr8gon,merryhime,mbc07,SirMangler,Sam-Belliveau,mahdihijazi')", 'type': 'internal_log'}
2026-07-18T23:45:26.521607	{'source': 'logging', 'level': 'INFO', 'pathname': '/nix/store/m89a38mxx677zd2j3gqq91c40d1i7dc6-central-env/lib/python3.13/site-packages/central/github/authz.py', 'lineno': 21, 'msg': 'Refreshing list of trusted users (from %s/%s)', 'args': "('dolphin-emu', 'trusted-developers')", 'type': 'internal_log'}
2026-07-18T23:40:26.521240	{'source': 'logging', 'level': 'INFO', 'pathname': '/nix/store/m89a38mxx677zd2j3gqq91c40d1i7dc6-central-env/lib/python3.13/site-packages/central/github/authz.py', 'lineno': 30, 'msg': 'New GH %s: %s', 'args': "('dolphin-emu/trusted-developers', 'EmptyChaos,unknownbrackets,CelestialAmber,Ebola16,Geotale,krnlyng,neobrain,CookiePLMonster,degasus,Stevoisiak,LillyJadeKatrin,iwubcode,kamiyo,Filoppi,hthh,rukai,Linkinworm,Parlane,Starsam80,meffij,phire,delroth,vladfi1,zackhow,malleoz,adamdmoss,NanoByte011,randomstuff,lioncash,mrgreywater,cristian64,Ziek,mimimi085181,deReeperJosh,bentley,jezze,orbea,ligfx,tygyh,magumagu,mathieui,skidau,kayru,endrift,jjdelvalle,Tilka,shonumi,Sintendo,Phatcat,TryTwo,marcan,JosJuice,zopieux,Buddybenj,OatmealDome,JoshuaVandaele,Techjar,Simonx22,JMC47,ColinDTaylor,CasualPokePlayer,Lobsterzelda,hrydgard,spxtr,archshift,corwin-mcknight,ShimmerGlass,aroulin,K0bin,LPFaint99,OrN,aldelaro5,skylersaleh,Helios747,CrystalGamma,nickbeth,tom-pratt,spycrab,magcius,RachelBryk,SuperSamus,AdmiralCurtiss,mmastrac,PatrickFerry,gwicks,BhaaLseN,leoetlino,rlnilsen,cscd98,riking,glennricster,Dentomologist,FioraAeterna,jloehr,comex,Linktothepast,galop1n,mandar1jn,RisingFog,moncefmechri,dreamsyntax,jordan-woyak,hdcmeta,MayImilae,Orphis,hackbar,Pokechu22,crediar,Gamer64ytb,booto,linkmauve,Tinob,Zopolis4,nullgemm,Alcaro,smurf3tte,yourWaifu,LAGonauta,sepalani,mitaclaw,JordanTheToaster,noahpistilli,DacoTaco,CrossVR,TellowKrinkle,Hydr8gon,merryhime,mbc07,SirMangler,Sam-Belliveau,mahdihijazi')", 'type': 'internal_log'}
2026-07-18T23:40:25.166133	{'source': 'logging', 'level': 'INFO', 'pathname': '/nix/store/m89a38mxx677zd2j3gqq91c40d1i7dc6-central-env/lib/python3.13/site-packages/central/github/authz.py', 'lineno': 21, 'msg': 'Refreshing list of trusted users (from %s/%s)', 'args': "('dolphin-emu', 'trusted-developers')", 'type': 'internal_log'}
2026-07-18T23:36:09.276883	{'source': 'logging', 'level': 'INFO', 'pathname': '/nix/store/m89a38mxx677zd2j3gqq91c40d1i7dc6-central-env/lib/python3.13/site-packages/central/github/authz.py', 'lineno': 30, 'msg': 'New GH %s: %s', 'args': "('dolphin-emu/core-developers', 'lioncash,Pokechu22,degasus,Helios747,iwubcode,spycrab,linkmauve,skidau,AdmiralCurtiss,Tilka,leoetlino,Parlane,JosJuice,Dentomologist,OatmealDome,phire,CrossVR,delroth,hrydgard,jordan-woyak')", 'type': 'internal_log'}
2026-07-18T23:36:09.001370	{'source': 'logging', 'level': 'INFO', 'pathname': '/nix/store/m89a38mxx677zd2j3gqq91c40d1i7dc6-central-env/lib/python3.13/site-packages/central/github/authz.py', 'lineno': 21, 'msg': 'Refreshing list of trusted users (from %s/%s)', 'args': "('dolphin-emu', 'core-developers')", 'type': 'internal_log'}
2026-07-18T23:35:25.165840	{'source': 'logging', 'level': 'INFO', 'pathname': '/nix/store/m89a38mxx677zd2j3gqq91c40d1i7dc6-central-env/lib/python3.13/site-packages/central/github/authz.py', 'lineno': 30, 'msg': 'New GH %s: %s', 'args': "('dolphin-emu/trusted-developers', 'EmptyChaos,unknownbrackets,CelestialAmber,Ebola16,Geotale,krnlyng,neobrain,CookiePLMonster,degasus,Stevoisiak,LillyJadeKatrin,iwubcode,kamiyo,Filoppi,hthh,rukai,Linkinworm,Parlane,Starsam80,meffij,phire,delroth,vladfi1,zackhow,malleoz,adamdmoss,NanoByte011,randomstuff,lioncash,mrgreywater,cristian64,Ziek,mimimi085181,deReeperJosh,bentley,jezze,orbea,ligfx,tygyh,magumagu,mathieui,skidau,kayru,endrift,jjdelvalle,Tilka,shonumi,Sintendo,Phatcat,TryTwo,marcan,JosJuice,zopieux,Buddybenj,OatmealDome,JoshuaVandaele,Techjar,Simonx22,JMC47,ColinDTaylor,CasualPokePlayer,Lobsterzelda,hrydgard,spxtr,archshift,corwin-mcknight,ShimmerGlass,aroulin,K0bin,LPFaint99,OrN,aldelaro5,skylersaleh,Helios747,CrystalGamma,nickbeth,tom-pratt,spycrab,magcius,RachelBryk,SuperSamus,AdmiralCurtiss,mmastrac,PatrickFerry,gwicks,BhaaLseN,leoetlino,rlnilsen,cscd98,riking,glennricster,Dentomologist,FioraAeterna,jloehr,comex,Linktothepast,galop1n,mandar1jn,RisingFog,moncefmechri,dreamsyntax,jordan-woyak,hdcmeta,MayImilae,Orphis,hackbar,Pokechu22,crediar,Gamer64ytb,booto,linkmauve,Tinob,Zopolis4,nullgemm,Alcaro,smurf3tte,yourWaifu,LAGonauta,sepalani,mitaclaw,JordanTheToaster,noahpistilli,DacoTaco,CrossVR,TellowKrinkle,Hydr8gon,merryhime,mbc07,SirMangler,Sam-Belliveau,mahdihijazi')", 'type': 'internal_log'}
2026-07-18T23:35:23.757017	{'source': 'logging', 'level': 'INFO', 'pathname': '/nix/store/m89a38mxx677zd2j3gqq91c40d1i7dc6-central-env/lib/python3.13/site-packages/central/github/authz.py', 'lineno': 21, 'msg': 'Refreshing list of trusted users (from %s/%s)', 'args': "('dolphin-emu', 'trusted-developers')", 'type': 'internal_log'}
2026-07-18T23:30:23.756662	{'source': 'logging', 'level': 'INFO', 'pathname': '/nix/store/m89a38mxx677zd2j3gqq91c40d1i7dc6-central-env/lib/python3.13/site-packages/central/github/authz.py', 'lineno': 30, 'msg': 'New GH %s: %s', 'args': "('dolphin-emu/trusted-developers', 'EmptyChaos,unknownbrackets,CelestialAmber,Ebola16,Geotale,krnlyng,neobrain,CookiePLMonster,degasus,Stevoisiak,LillyJadeKatrin,iwubcode,kamiyo,Filoppi,hthh,rukai,Linkinworm,Parlane,Starsam80,meffij,phire,delroth,vladfi1,zackhow,malleoz,adamdmoss,NanoByte011,randomstuff,lioncash,mrgreywater,cristian64,Ziek,mimimi085181,deReeperJosh,bentley,jezze,orbea,ligfx,tygyh,magumagu,mathieui,skidau,kayru,endrift,jjdelvalle,Tilka,shonumi,Sintendo,Phatcat,TryTwo,marcan,JosJuice,zopieux,Buddybenj,OatmealDome,JoshuaVandaele,Techjar,Simonx22,JMC47,ColinDTaylor,CasualPokePlayer,Lobsterzelda,hrydgard,spxtr,archshift,corwin-mcknight,ShimmerGlass,aroulin,K0bin,LPFaint99,OrN,aldelaro5,skylersaleh,Helios747,CrystalGamma,nickbeth,tom-pratt,spycrab,magcius,RachelBryk,SuperSamus,AdmiralCurtiss,mmastrac,PatrickFerry,gwicks,BhaaLseN,leoetlino,rlnilsen,cscd98,riking,glennricster,Dentomologist,FioraAeterna,jloehr,comex,Linktothepast,galop1n,mandar1jn,RisingFog,moncefmechri,dreamsyntax,jordan-woyak,hdcmeta,MayImilae,Orphis,hackbar,Pokechu22,crediar,Gamer64ytb,booto,linkmauve,Tinob,Zopolis4,nullgemm,Alcaro,smurf3tte,yourWaifu,LAGonauta,sepalani,mitaclaw,JordanTheToaster,noahpistilli,DacoTaco,CrossVR,TellowKrinkle,Hydr8gon,merryhime,mbc07,SirMangler,Sam-Belliveau,mahdihijazi')", 'type': 'internal_log'}
2026-07-18T23:30:22.328883	{'source': 'logging', 'level': 'INFO', 'pathname': '/nix/store/m89a38mxx677zd2j3gqq91c40d1i7dc6-central-env/lib/python3.13/site-packages/central/github/authz.py', 'lineno': 21, 'msg': 'Refreshing list of trusted users (from %s/%s)', 'args': "('dolphin-emu', 'trusted-developers')", 'type': 'internal_log'}
2026-07-18T23:26:09.001110	{'source': 'logging', 'level': 'INFO', 'pathname': '/nix/store/m89a38mxx677zd2j3gqq91c40d1i7dc6-central-env/lib/python3.13/site-packages/central/github/authz.py', 'lineno': 30, 'msg': 'New GH %s: %s', 'args': "('dolphin-emu/core-developers', 'lioncash,Pokechu22,degasus,Helios747,iwubcode,spycrab,linkmauve,skidau,AdmiralCurtiss,Tilka,leoetlino,Parlane,JosJuice,Dentomologist,OatmealDome,phire,CrossVR,delroth,hrydgard,jordan-woyak')", 'type': 'internal_log'}
2026-07-18T23:26:08.731296	{'source': 'logging', 'level': 'INFO', 'pathname': '/nix/store/m89a38mxx677zd2j3gqq91c40d1i7dc6-central-env/lib/python3.13/site-packages/central/github/authz.py', 'lineno': 21, 'msg': 'Refreshing list of trusted users (from %s/%s)', 'args': "('dolphin-emu', 'core-developers')", 'type': 'internal_log'}
2026-07-18T23:25:22.328553	{'source': 'logging', 'level': 'INFO', 'pathname': '/nix/store/m89a38mxx677zd2j3gqq91c40d1i7dc6-central-env/lib/python3.13/site-packages/central/github/authz.py', 'lineno': 30, 'msg': 'New GH %s: %s', 'args': "('dolphin-emu/trusted-developers', 'EmptyChaos,unknownbrackets,CelestialAmber,Ebola16,Geotale,krnlyng,neobrain,CookiePLMonster,degasus,Stevoisiak,LillyJadeKatrin,iwubcode,kamiyo,Filoppi,hthh,rukai,Linkinworm,Parlane,Starsam80,meffij,phire,delroth,vladfi1,zackhow,malleoz,adamdmoss,NanoByte011,randomstuff,lioncash,mrgreywater,cristian64,Ziek,mimimi085181,deReeperJosh,bentley,jezze,orbea,ligfx,tygyh,magumagu,mathieui,skidau,kayru,endrift,jjdelvalle,Tilka,shonumi,Sintendo,Phatcat,TryTwo,marcan,JosJuice,zopieux,Buddybenj,OatmealDome,JoshuaVandaele,Techjar,Simonx22,JMC47,ColinDTaylor,CasualPokePlayer,Lobsterzelda,hrydgard,spxtr,archshift,corwin-mcknight,ShimmerGlass,aroulin,K0bin,LPFaint99,OrN,aldelaro5,skylersaleh,Helios747,CrystalGamma,nickbeth,tom-pratt,spycrab,magcius,RachelBryk,SuperSamus,AdmiralCurtiss,mmastrac,PatrickFerry,gwicks,BhaaLseN,leoetlino,rlnilsen,cscd98,riking,glennricster,Dentomologist,FioraAeterna,jloehr,comex,Linktothepast,galop1n,mandar1jn,RisingFog,moncefmechri,dreamsyntax,jordan-woyak,hdcmeta,MayImilae,Orphis,hackbar,Pokechu22,crediar,Gamer64ytb,booto,linkmauve,Tinob,Zopolis4,nullgemm,Alcaro,smurf3tte,yourWaifu,LAGonauta,sepalani,mitaclaw,JordanTheToaster,noahpistilli,DacoTaco,CrossVR,TellowKrinkle,Hydr8gon,merryhime,mbc07,SirMangler,Sam-Belliveau,mahdihijazi')", 'type': 'internal_log'}
2026-07-18T23:25:20.698127	{'source': 'logging', 'level': 'INFO', 'pathname': '/nix/store/m89a38mxx677zd2j3gqq91c40d1i7dc6-central-env/lib/python3.13/site-packages/central/github/authz.py', 'lineno': 21, 'msg': 'Refreshing list of trusted users (from %s/%s)', 'args': "('dolphin-emu', 'trusted-developers')", 'type': 'internal_log'}
2026-07-18T23:20:20.697778	{'source': 'logging', 'level': 'INFO', 'pathname': '/nix/store/m89a38mxx677zd2j3gqq91c40d1i7dc6-central-env/lib/python3.13/site-packages/central/github/authz.py', 'lineno': 30, 'msg': 'New GH %s: %s', 'args': "('dolphin-emu/trusted-developers', 'EmptyChaos,unknownbrackets,CelestialAmber,Ebola16,Geotale,krnlyng,neobrain,CookiePLMonster,degasus,Stevoisiak,LillyJadeKatrin,iwubcode,kamiyo,Filoppi,hthh,rukai,Linkinworm,Parlane,Starsam80,meffij,phire,delroth,vladfi1,zackhow,malleoz,adamdmoss,NanoByte011,randomstuff,lioncash,mrgreywater,cristian64,Ziek,mimimi085181,deReeperJosh,bentley,jezze,orbea,ligfx,tygyh,magumagu,mathieui,skidau,kayru,endrift,jjdelvalle,Tilka,shonumi,Sintendo,Phatcat,TryTwo,marcan,JosJuice,zopieux,Buddybenj,OatmealDome,JoshuaVandaele,Techjar,Simonx22,JMC47,ColinDTaylor,CasualPokePlayer,Lobsterzelda,hrydgard,spxtr,archshift,corwin-mcknight,ShimmerGlass,aroulin,K0bin,LPFaint99,OrN,aldelaro5,skylersaleh,Helios747,CrystalGamma,nickbeth,tom-pratt,spycrab,magcius,RachelBryk,SuperSamus,AdmiralCurtiss,mmastrac,PatrickFerry,gwicks,BhaaLseN,leoetlino,rlnilsen,cscd98,riking,glennricster,Dentomologist,FioraAeterna,jloehr,comex,Linktothepast,galop1n,mandar1jn,RisingFog,moncefmechri,dreamsyntax,jordan-woyak,hdcmeta,MayImilae,Orphis,hackbar,Pokechu22,crediar,Gamer64ytb,booto,linkmauve,Tinob,Zopolis4,nullgemm,Alcaro,smurf3tte,yourWaifu,LAGonauta,sepalani,mitaclaw,JordanTheToaster,noahpistilli,DacoTaco,CrossVR,TellowKrinkle,Hydr8gon,merryhime,mbc07,SirMangler,Sam-Belliveau,mahdihijazi')", 'type': 'internal_log'}
2026-07-18T23:20:19.363585	{'source': 'logging', 'level': 'INFO', 'pathname': '/nix/store/m89a38mxx677zd2j3gqq91c40d1i7dc6-central-env/lib/python3.13/site-packages/central/github/authz.py', 'lineno': 21, 'msg': 'Refreshing list of trusted users (from %s/%s)', 'args': "('dolphin-emu', 'trusted-developers')", 'type': 'internal_log'}
2026-07-18T23:16:08.731048	{'source': 'logging', 'level': 'INFO', 'pathname': '/nix/store/m89a38mxx677zd2j3gqq91c40d1i7dc6-central-env/lib/python3.13/site-packages/central/github/authz.py', 'lineno': 30, 'msg': 'New GH %s: %s', 'args': "('dolphin-emu/core-developers', 'lioncash,Pokechu22,degasus,Helios747,iwubcode,spycrab,linkmauve,skidau,AdmiralCurtiss,Tilka,leoetlino,Parlane,JosJuice,Dentomologist,OatmealDome,phire,CrossVR,delroth,hrydgard,jordan-woyak')", 'type': 'internal_log'}
2026-07-18T23:16:08.246892	{'source': 'logging', 'level': 'INFO', 'pathname': '/nix/store/m89a38mxx677zd2j3gqq91c40d1i7dc6-central-env/lib/python3.13/site-packages/central/github/authz.py', 'lineno': 21, 'msg': 'Refreshing list of trusted users (from %s/%s)', 'args': "('dolphin-emu', 'core-developers')", 'type': 'internal_log'}
2026-07-18T23:15:19.363244	{'source': 'logging', 'level': 'INFO', 'pathname': '/nix/store/m89a38mxx677zd2j3gqq91c40d1i7dc6-central-env/lib/python3.13/site-packages/central/github/authz.py', 'lineno': 30, 'msg': 'New GH %s: %s', 'args': "('dolphin-emu/trusted-developers', 'EmptyChaos,unknownbrackets,CelestialAmber,Ebola16,Geotale,krnlyng,neobrain,CookiePLMonster,degasus,Stevoisiak,LillyJadeKatrin,iwubcode,kamiyo,Filoppi,hthh,rukai,Linkinworm,Parlane,Starsam80,meffij,phire,delroth,vladfi1,zackhow,malleoz,adamdmoss,NanoByte011,randomstuff,lioncash,mrgreywater,cristian64,Ziek,mimimi085181,deReeperJosh,bentley,jezze,orbea,ligfx,tygyh,magumagu,mathieui,skidau,kayru,endrift,jjdelvalle,Tilka,shonumi,Sintendo,Phatcat,TryTwo,marcan,JosJuice,zopieux,Buddybenj,OatmealDome,JoshuaVandaele,Techjar,Simonx22,JMC47,ColinDTaylor,CasualPokePlayer,Lobsterzelda,hrydgard,spxtr,archshift,corwin-mcknight,ShimmerGlass,aroulin,K0bin,LPFaint99,OrN,aldelaro5,skylersaleh,Helios747,CrystalGamma,nickbeth,tom-pratt,spycrab,magcius,RachelBryk,SuperSamus,AdmiralCurtiss,mmastrac,PatrickFerry,gwicks,BhaaLseN,leoetlino,rlnilsen,cscd98,riking,glennricster,Dentomologist,FioraAeterna,jloehr,comex,Linktothepast,galop1n,mandar1jn,RisingFog,moncefmechri,dreamsyntax,jordan-woyak,hdcmeta,MayImilae,Orphis,hackbar,Pokechu22,crediar,Gamer64ytb,booto,linkmauve,Tinob,Zopolis4,nullgemm,Alcaro,smurf3tte,yourWaifu,LAGonauta,sepalani,mitaclaw,JordanTheToaster,noahpistilli,DacoTaco,CrossVR,TellowKrinkle,Hydr8gon,merryhime,mbc07,SirMangler,Sam-Belliveau,mahdihijazi')", 'type': 'internal_log'}
2026-07-18T23:15:17.793122	{'source': 'logging', 'level': 'INFO', 'pathname': '/nix/store/m89a38mxx677zd2j3gqq91c40d1i7dc6-central-env/lib/python3.13/site-packages/central/github/authz.py', 'lineno': 21, 'msg': 'Refreshing list of trusted users (from %s/%s)', 'args': "('dolphin-emu', 'trusted-developers')", 'type': 'internal_log'}
2026-07-18T23:10:17.792783	{'source': 'logging', 'level': 'INFO', 'pathname': '/nix/store/m89a38mxx677zd2j3gqq91c40d1i7dc6-central-env/lib/python3.13/site-packages/central/github/authz.py', 'lineno': 30, 'msg': 'New GH %s: %s', 'args': "('dolphin-emu/trusted-developers', 'EmptyChaos,unknownbrackets,CelestialAmber,Ebola16,Geotale,krnlyng,neobrain,CookiePLMonster,degasus,Stevoisiak,LillyJadeKatrin,iwubcode,kamiyo,Filoppi,hthh,rukai,Linkinworm,Parlane,Starsam80,meffij,phire,delroth,vladfi1,zackhow,malleoz,adamdmoss,NanoByte011,randomstuff,lioncash,mrgreywater,cristian64,Ziek,mimimi085181,deReeperJosh,bentley,jezze,orbea,ligfx,tygyh,magumagu,mathieui,skidau,kayru,endrift,jjdelvalle,Tilka,shonumi,Sintendo,Phatcat,TryTwo,marcan,JosJuice,zopieux,Buddybenj,OatmealDome,JoshuaVandaele,Techjar,Simonx22,JMC47,ColinDTaylor,CasualPokePlayer,Lobsterzelda,hrydgard,spxtr,archshift,corwin-mcknight,ShimmerGlass,aroulin,K0bin,LPFaint99,OrN,aldelaro5,skylersaleh,Helios747,CrystalGamma,nickbeth,tom-pratt,spycrab,magcius,RachelBryk,SuperSamus,AdmiralCurtiss,mmastrac,PatrickFerry,gwicks,BhaaLseN,leoetlino,rlnilsen,cscd98,riking,glennricster,Dentomologist,FioraAeterna,jloehr,comex,Linktothepast,galop1n,mandar1jn,RisingFog,moncefmechri,dreamsyntax,jordan-woyak,hdcmeta,MayImilae,Orphis,hackbar,Pokechu22,crediar,Gamer64ytb,booto,linkmauve,Tinob,Zopolis4,nullgemm,Alcaro,smurf3tte,yourWaifu,LAGonauta,sepalani,mitaclaw,JordanTheToaster,noahpistilli,DacoTaco,CrossVR,TellowKrinkle,Hydr8gon,merryhime,mbc07,SirMangler,Sam-Belliveau,mahdihijazi')", 'type': 'internal_log'}
2026-07-18T23:10:16.147926	{'source': 'logging', 'level': 'INFO', 'pathname': '/nix/store/m89a38mxx677zd2j3gqq91c40d1i7dc6-central-env/lib/python3.13/site-packages/central/github/authz.py', 'lineno': 21, 'msg': 'Refreshing list of trusted users (from %s/%s)', 'args': "('dolphin-emu', 'trusted-developers')", 'type': 'internal_log'}
2026-07-18T23:06:08.246651	{'source': 'logging', 'level': 'INFO', 'pathname': '/nix/store/m89a38mxx677zd2j3gqq91c40d1i7dc6-central-env/lib/python3.13/site-packages/central/github/authz.py', 'lineno': 30, 'msg': 'New GH %s: %s', 'args': "('dolphin-emu/core-developers', 'lioncash,Pokechu22,degasus,Helios747,iwubcode,spycrab,linkmauve,skidau,AdmiralCurtiss,Tilka,leoetlino,Parlane,JosJuice,Dentomologist,OatmealDome,phire,CrossVR,delroth,hrydgard,jordan-woyak')", 'type': 'internal_log'}

Recent 'issue' events

2026-07-18T06:44:48.106632	{'source': 'redmine', 'new': True, 'update': 0, 'issue': 14102, 'title': '[Feature Request] Change definition of lag frames', 'author': 'InputEvelution', 'type': 'issue'}
2026-07-17T20:52:56.400374	{'source': 'redmine', 'new': False, 'update': 4, 'issue': 14101, 'title': 'Keyboard input stops working in games after first launch (Flatpak, X11, Linux) ', 'author': 'Gabgabgab', 'type': 'issue'}
2026-07-17T19:58:25.747073	{'source': 'redmine', 'new': False, 'update': 3, 'issue': 14101, 'title': 'Keyboard input stops working in games after first launch (Flatpak, X11, Linux) ', 'author': 'Billiard26', 'type': 'issue'}
2026-07-17T19:58:20.233758	{'source': 'redmine', 'new': False, 'update': 2, 'issue': 14101, 'title': 'Keyboard input stops working in games after first launch (Flatpak, X11, Linux) ', 'author': 'Billiard26', 'type': 'issue'}
2026-07-17T19:53:59.404573	{'source': 'redmine', 'new': True, 'update': 0, 'issue': 14101, 'title': 'Keyboard input stops working in games after first launch (Flatpak, X11, Linux) ', 'author': 'Gabgabgab', 'type': 'issue'}
2026-07-17T11:40:57.083561	{'source': 'redmine', 'new': True, 'update': 0, 'issue': 14100, 'title': 'Feature Request: Group Multi-Disc Games into a Single Game List Entry ', 'author': 'rayu25sao@gmail.com', 'type': 'issue'}
2026-07-16T20:34:26.152814	{'source': 'redmine', 'new': False, 'update': 2, 'issue': 14094, 'title': 'BBA HLE does not listen on Port 9003 for HomeLand (TCP)', 'author': 'sepalani', 'type': 'issue'}
2026-07-16T09:19:35.248645	{'source': 'redmine', 'new': True, 'update': 0, 'issue': 14099, 'title': 'Timing issues with DSP HLE cause a deadlock in Super Mario 64 Homebrew GameCube/Wii port', 'author': 'Adamillo', 'type': 'issue'}
2026-07-15T22:41:22.256070	{'source': 'redmine', 'new': True, 'update': 0, 'issue': 14098, 'title': 'Skylanders Trap Team Wii crashes when loading Midnight Museum Adventure Pack', 'author': 'mresop', 'type': 'issue'}
2026-07-14T19:04:50.932238	{'source': 'redmine', 'new': False, 'update': 3, 'issue': 14095, 'title': 'Crash when removing a pack in the Resource Pack Manager', 'author': 'Dentomologist', 'type': 'issue'}
2026-07-13T16:24:14.623838	{'source': 'redmine', 'new': False, 'update': 2, 'issue': 14097, 'title': 'Manual Inject/Eject Card ', 'author': 'Billiard26', 'type': 'issue'}
2026-07-13T15:16:15.142823	{'source': 'redmine', 'new': True, 'update': 0, 'issue': 14097, 'title': 'Manual Inject/Eject Card ', 'author': 'Taiyakisantarou', 'type': 'issue'}
2026-07-13T12:47:51.487850	{'source': 'redmine', 'new': False, 'update': 2, 'issue': 14082, 'title': 'flatpak dolphin-tool convert --help format option shows [%choices] instead of actual choices', 'author': 'JoshuaVandaele', 'type': 'issue'}
2026-07-12T18:57:17.511242	{'source': 'redmine', 'new': True, 'update': 0, 'issue': 14096, 'title': 'Dolphin 2606 on Windows 11 black screen with white square in the middle.', 'author': 'naruto020499', 'type': 'issue'}
2026-07-12T00:38:46.341074	{'source': 'redmine', 'new': False, 'update': 2, 'issue': 14095, 'title': 'Crash when removing a pack in the Resource Pack Manager', 'author': 'Dentomologist', 'type': 'issue'}

Recent 'new_dev_version' events

2026-07-18T10:34:57.579792	{'source': 'repomanager', 'hash': '415ec4de182034179143231e84c17dbcdf8be8aa', 'branch': 'master', 'shortrev': '2606-186', 'author': 'JosJuice', 'message': 'Merge pull request #14673 from tommywaaf/android-dolphinbar-balance-board\n\nAndroid: Route DolphinBar Balance Board to the Balance Board slot', 'url': 'https://github.com/dolphin-emu/dolphin/commit/415ec4de182034179143231e84c17dbcdf8be8aa', 'type': 'new_dev_version'}
2026-07-15T20:58:06.100212	{'source': 'repomanager', 'hash': 'b6d8bc299ee7d03496d624b2e6b9a18d70522435', 'branch': 'master', 'shortrev': '2606-184', 'author': 'Scott Mansell', 'message': 'Merge pull request #14726 from JosJuice/gcadapter-deregister-on-thread-end\n\nGCAdapter: Deregister callback when scan thread exits', 'url': 'https://github.com/dolphin-emu/dolphin/commit/b6d8bc299ee7d03496d624b2e6b9a18d70522435', 'type': 'new_dev_version'}
2026-07-15T20:08:16.998571	{'source': 'repomanager', 'hash': '81402ca6aa93503be38736b5dd6d8d96fcbfd0d5', 'branch': 'master', 'shortrev': '2606-182', 'author': 'Admiral H. Curtiss', 'message': 'Merge pull request #14732 from khang06/small-tmd-check\n\nIOS/ES: Prevent reading TMDs that are too small', 'url': 'https://github.com/dolphin-emu/dolphin/commit/81402ca6aa93503be38736b5dd6d8d96fcbfd0d5', 'type': 'new_dev_version'}
2026-07-15T05:48:34.820562	{'source': 'repomanager', 'hash': 'fd8391a85241d1b359d662342c5c66f8f4b96d10', 'branch': 'master', 'shortrev': '2606-180', 'author': 'Scott Mansell', 'message': 'Merge pull request #14263 from JoshuaVandaele/ccache-toggle\n\nCCache: Set as opt-in by default', 'url': 'https://github.com/dolphin-emu/dolphin/commit/fd8391a85241d1b359d662342c5c66f8f4b96d10', 'type': 'new_dev_version'}
2026-07-15T05:46:57.841066	{'source': 'repomanager', 'hash': '566519d13553c054980b8eed390c1f26a1f866fa', 'branch': 'master', 'shortrev': '2606-178', 'author': 'Scott Mansell', 'message': 'Merge pull request #14222 from Sintendo/ppcsymboldb-lookup\n\nPPCSymbolDB: Avoid double lookups', 'url': 'https://github.com/dolphin-emu/dolphin/commit/566519d13553c054980b8eed390c1f26a1f866fa', 'type': 'new_dev_version'}
2026-07-15T05:08:15.732511	{'source': 'repomanager', 'hash': 'ee5eba860d999b2bf7ca1b5011877ab4a78f56d2', 'branch': 'master', 'shortrev': '2606-176', 'author': 'Scott Mansell', 'message': 'Merge pull request #14651 from DacoTaco/fixes/dolalignment\n\nfixes: make dolreader validate section addresses and sizes', 'url': 'https://github.com/dolphin-emu/dolphin/commit/ee5eba860d999b2bf7ca1b5011877ab4a78f56d2', 'type': 'new_dev_version'}
2026-07-15T05:01:50.525884	{'source': 'repomanager', 'hash': '552126a0e6524ac7e0e8f5ec40ca9dbd06291071', 'branch': 'master', 'shortrev': '2606-174', 'author': 'Scott Mansell', 'message': 'Merge pull request #14675 from JosJuice/game-ini-gbihf-texcache\n\nGameSettings: Remove SafeTextureCacheColorSamples from gbihf', 'url': 'https://github.com/dolphin-emu/dolphin/commit/552126a0e6524ac7e0e8f5ec40ca9dbd06291071', 'type': 'new_dev_version'}
2026-07-15T05:00:32.544270	{'source': 'repomanager', 'hash': '1ab4403c236fa34ce8807c4895f705913217372d', 'branch': 'master', 'shortrev': '2606-172', 'author': 'Scott Mansell', 'message': 'Merge pull request #14703 from JoshuaVandaele/miniupnpc-arm64-cross\n\nExternals/miniupnpc: Disable warnings', 'url': 'https://github.com/dolphin-emu/dolphin/commit/1ab4403c236fa34ce8807c4895f705913217372d', 'type': 'new_dev_version'}
2026-07-15T04:45:47.823439	{'source': 'repomanager', 'hash': 'd895ed7d5cb493aa461a1a0aedc683c0c3b70925', 'branch': 'master', 'shortrev': '2606-170', 'author': 'Scott Mansell', 'message': 'Merge pull request #14722 from idkwhere1sthisname/master\n\nIOS/ES: allow Wii System Transfer and WagonCompat Transfer Tool to pass SetUID check', 'url': 'https://github.com/dolphin-emu/dolphin/commit/d895ed7d5cb493aa461a1a0aedc683c0c3b70925', 'type': 'new_dev_version'}
2026-07-14T20:52:12.950807	{'source': 'repomanager', 'hash': 'd3b2943807dd0073f7767947466dd73cccfef319', 'branch': 'master', 'shortrev': '2606-168', 'author': 'Dentomologist', 'message': 'Merge pull request #14705 from JosJuice/directoryblob-dtk-comment\n\nDiscIO: Add DTK alignment comment in DirectoryBlob', 'url': 'https://github.com/dolphin-emu/dolphin/commit/d3b2943807dd0073f7767947466dd73cccfef319', 'type': 'new_dev_version'}
2026-07-14T18:58:49.954913	{'source': 'repomanager', 'hash': '00beaa84a550fe35755910d96182d04e0996450b', 'branch': 'master', 'shortrev': '2606-166', 'author': 'Dentomologist', 'message': 'Merge pull request #14730 from JoshuaVandaele/contributing-cxx-standard\n\nContributing.md: Update C++20 mentions to C++23', 'url': 'https://github.com/dolphin-emu/dolphin/commit/00beaa84a550fe35755910d96182d04e0996450b', 'type': 'new_dev_version'}
2026-07-14T17:26:19.855690	{'source': 'repomanager', 'hash': '37726b610d3e6596b6af505178e6bf074c949b26', 'branch': 'master', 'shortrev': '2606-164', 'author': 'Admiral H. Curtiss', 'message': 'Merge pull request #14723 from Dentomologist/resource_pack_manager_fix_crash_when_removing_pack\n\nResourcePackManager: Fix crash when removing pack and properly update list', 'url': 'https://github.com/dolphin-emu/dolphin/commit/37726b610d3e6596b6af505178e6bf074c949b26', 'type': 'new_dev_version'}
2026-07-14T17:15:03.803832	{'source': 'repomanager', 'hash': 'fee15d96ad094f3a91a1b8074f8d1a113d7d55c2', 'branch': 'master', 'shortrev': '2606-161', 'author': 'Admiral H. Curtiss', 'message': 'Merge pull request #14719 from cscd98/m3u-fix\n\nm3u: normalize line endings except win32', 'url': 'https://github.com/dolphin-emu/dolphin/commit/fee15d96ad094f3a91a1b8074f8d1a113d7d55c2', 'type': 'new_dev_version'}
2026-07-14T16:49:20.825455	{'source': 'repomanager', 'hash': '1b67ed71f40cf7b7afcac68bda08a52d8d44f164', 'branch': 'master', 'shortrev': '2606-159', 'author': 'JosJuice', 'message': 'Merge pull request #14357 from Windsurf7/sonicunleashed-gameini\n\nGameINI: Add codes to Sonic Unleashed', 'url': 'https://github.com/dolphin-emu/dolphin/commit/1b67ed71f40cf7b7afcac68bda08a52d8d44f164', 'type': 'new_dev_version'}
2026-07-14T16:38:43.321227	{'source': 'repomanager', 'hash': '19729879cbf85e3c24363c2af443cacfcc80df43', 'branch': 'master', 'shortrev': '2606-157', 'author': 'JosJuice', 'message': 'Merge pull request #14711 from tom-pratt/landscape-netplay-screens\n\nAndroid: Netplay layout update for landscape navigation', 'url': 'https://github.com/dolphin-emu/dolphin/commit/19729879cbf85e3c24363c2af443cacfcc80df43', 'type': 'new_dev_version'}
2026-07-14T08:24:28.677007	{'source': 'repomanager', 'hash': '09fbe2a93000127d56dde527179e1b41ba804099', 'branch': 'master', 'shortrev': '2606-155', 'author': 'Scott Mansell', 'message': 'Merge pull request #14729 from JoshuaVandaele/fix-clang-libstdcpp\n\nPerformanceMetrics: Fix compiling using clang&libstdc++', 'url': 'https://github.com/dolphin-emu/dolphin/commit/09fbe2a93000127d56dde527179e1b41ba804099', 'type': 'new_dev_version'}
2026-07-13T06:47:23.821390	{'source': 'repomanager', 'hash': 'cdaf67c6ce4b5a23c3dd759a439d2bf434396791', 'branch': 'master', 'shortrev': '2606-153', 'author': 'Dentomologist', 'message': 'Merge pull request #14643 from Dentomologist/windows_git_bash_fix_command_line_output\n\nWindows: Fix command line output not displaying when using Git Bash', 'url': 'https://github.com/dolphin-emu/dolphin/commit/cdaf67c6ce4b5a23c3dd759a439d2bf434396791', 'type': 'new_dev_version'}
2026-07-13T06:28:32.452668	{'source': 'repomanager', 'hash': 'd6d25b5302073dd4292a2286c753c4b344aec2da', 'branch': 'master', 'shortrev': '2606-151', 'author': 'Dentomologist', 'message': 'Merge pull request #14351 from Windsurf7/nightsjod-gameini\n\nGameINI: Add codes to NiGHTS Journey of Dreams', 'url': 'https://github.com/dolphin-emu/dolphin/commit/d6d25b5302073dd4292a2286c753c4b344aec2da', 'type': 'new_dev_version'}
2026-07-13T05:00:56.238176	{'source': 'repomanager', 'hash': '990b4212338375b37a6ab9d480af5f3f9e408243', 'branch': 'master', 'shortrev': '2606-149', 'author': 'OatmealDome', 'message': 'Merge pull request #14728 from Simonx22/android/api37-ndk30-dependency-updates\n\nAndroid: Update dependencies and build tools', 'url': 'https://github.com/dolphin-emu/dolphin/commit/990b4212338375b37a6ab9d480af5f3f9e408243', 'type': 'new_dev_version'}
2026-07-13T05:00:47.808880	{'source': 'repomanager', 'hash': 'f544fbc0aed5b21777003c25c21c85ba846b2093', 'branch': 'master', 'shortrev': '2606-147', 'author': 'OatmealDome', 'message': 'Merge pull request #14630 from Simonx22/android/convert-contenthandler-to-kotlin\n\nAndroid: Convert ContentHandler to Kotlin and fix warnings', 'url': 'https://github.com/dolphin-emu/dolphin/commit/f544fbc0aed5b21777003c25c21c85ba846b2093', 'type': 'new_dev_version'}
2026-07-13T00:20:49.215873	{'source': 'repomanager', 'hash': 'b947a11380d02b30592c81ff78c49023e399f681', 'branch': 'master', 'shortrev': '2606-145', 'author': 'Dentomologist', 'message': 'Merge pull request #14356 from Windsurf7/sonicstorybook-gameini\n\nGameINI: Add codes to Sonic Storybook games', 'url': 'https://github.com/dolphin-emu/dolphin/commit/b947a11380d02b30592c81ff78c49023e399f681', 'type': 'new_dev_version'}
2026-07-11T23:34:49.315972	{'source': 'repomanager', 'hash': 'fc9fd6952a62c4fe48acc00333ce360cb47b57c7', 'branch': 'master', 'shortrev': '2606-143', 'author': 'Scott Mansell', 'message': 'Merge pull request #14665 from cristian64/simulated_memory_size\n\nCore: Adjust emulated memory size automatically.', 'url': 'https://github.com/dolphin-emu/dolphin/commit/fc9fd6952a62c4fe48acc00333ce360cb47b57c7', 'type': 'new_dev_version'}

Recent 'notification' events

2026-07-18T23:41:40.251881	{'source': 'notifications', 'msg': '[\x1f\x0313dolphin-emu/dolphin\x03\x1f] \x0303t\ufeffhethiny\x03 commented on #14731 (Convert To WBFS Support): \x1f\x0302https://dolp.in/pr14731#issuecomment-5013376425\x03\x1f', 'type': 'notification'}
2026-07-18T23:41:29.025116	{'source': 'notifications', 'msg': '[\x1f\x0313dolphin-emu/dolphin\x03\x1f] \x0303p\ufeffhire\x03 commented on #14731 24b41d: \x1f\x0302https://dolp.in/pr14731#discussion_r3609425504\x03\x1f', 'type': 'notification'}
2026-07-18T23:37:37.476476	{'source': 'notifications', 'msg': '[\x1f\x0313dolphin-emu/dolphin\x03\x1f] \x0303t\ufeffhethiny\x03 commented on #14731 24b41d: \x1f\x0302https://dolp.in/pr14731#discussion_r3609419546\x03\x1f', 'type': 'notification'}
2026-07-18T23:36:12.676971	{'source': 'notifications', 'msg': '[\x1f\x0313dolphin-emu/dolphin\x03\x1f] \x0303t\ufeffhethiny\x03 commented on #14731 24b41d: \x1f\x0302https://dolp.in/pr14731#discussion_r3609417157\x03\x1f', 'type': 'notification'}
2026-07-18T23:33:15.220049	{'source': 'notifications', 'msg': '[\x1f\x0313dolphin-emu/dolphin\x03\x1f] \x0303t\ufeffhethiny\x03 commented on #14731 24b41d: \x1f\x0302https://dolp.in/pr14731#discussion_r3609413351\x03\x1f', 'type': 'notification'}
2026-07-18T23:29:02.353349	{'source': 'notifications', 'msg': '[\x1f\x0313dolphin-emu/dolphin\x03\x1f] \x0303t\ufeffhethiny\x03 commented on #14731 24b41d: \x1f\x0302https://dolp.in/pr14731#discussion_r3609408071\x03\x1f', 'type': 'notification'}
2026-07-18T23:14:48.024647	{'source': 'notifications', 'msg': '[\x1f\x0313dolphin-emu/dolphin\x03\x1f] \x0303p\ufeffhire\x03 commented on #14731 24b41d: \x1f\x0302https://dolp.in/pr14731#discussion_r3609382108\x03\x1f', 'type': 'notification'}
2026-07-18T23:06:02.346713	{'source': 'notifications', 'msg': '[\x1f\x0313dolphin-emu/dolphin\x03\x1f] \x0303p\ufeffhire\x03 reviewed and commented on pull request #14731 (Convert To WBFS Support): \x1f\x0302https://dolp.in/pr14731#pullrequestreview-4729447426\x03\x1f', 'type': 'notification'}
2026-07-18T22:54:54.428882	{'source': 'notifications', 'msg': '[\x1f\x0313dolphin-emu/dolphin\x03\x1f] \x0303p\ufeffhire\x03 approved pull request #14475 (CMake: Replace the Visual Studio project): \x1f\x0302https://dolp.in/pr14475#pullrequestreview-4729435306\x03\x1f', 'type': 'notification'}
2026-07-18T22:51:01.273386	{'source': 'notifications', 'msg': '[\x1f\x0313dolphin-emu/sadm\x03\x1f] \x0303p\ufeffhire\x03 approved pull request #204 (Update buildbot configuration to use new CMake presets): \x1f\x0302https://github.com/dolphin-emu/sadm/pull/204#pullrequestreview-4729430995\x03\x1f', 'type': 'notification'}
2026-07-18T22:41:10.191275	{'source': 'notifications', 'msg': '[\x1f\x0313dolphin-emu/sadm\x03\x1f] \x0303p\ufeffhire\x03 commented on #204 (Update buildbot configuration to use new CMake presets): \x1f\x0302https://github.com/dolphin-emu/sadm/pull/204#issuecomment-5013205285\x03\x1f', 'type': 'notification'}
2026-07-18T22:26:25.584937	{'source': 'notifications', 'msg': '[\x1f\x0313dolphin-emu/dolphin\x03\x1f] \x0303p\ufeffhire\x03 reviewed and commented on pull request #14731 (Convert To WBFS Support): \x1f\x0302https://dolp.in/pr14731#pullrequestreview-4729322283\x03\x1f', 'type': 'notification'}
2026-07-18T22:17:00.816488	{'source': 'notifications', 'msg': '[\x1f\x0313dolphin-emu/dolphin\x03\x1f] \x0303J\ufeffoshuaVandaele\x03 commented on #14731 (Convert To WBFS Support): \x1f\x0302https://dolp.in/pr14731#issuecomment-5013135939\x03\x1f', 'type': 'notification'}
2026-07-18T22:03:31.011093	{'source': 'notifications', 'msg': '[\x1f\x0313dolphin-emu/dolphin\x03\x1f] \x0303t\ufeffhethiny\x03 commented on #14731 (Convert To WBFS Support): \x1f\x0302https://dolp.in/pr14731#issuecomment-5013096819\x03\x1f', 'type': 'notification'}
2026-07-18T20:58:04.066340	{'source': 'notifications', 'msg': '[\x1f\x0313dolphin-emu/dolphin\x03\x1f] \x0303t\ufeffhethiny\x03 commented on #14731 (Convert To WBFS Support): \x1f\x0302https://dolp.in/pr14731#issuecomment-5012898695\x03\x1f', 'type': 'notification'}
2026-07-18T20:47:17.770099	{'source': 'notifications', 'msg': '[\x1f\x0313dolphin-emu/dolphin\x03\x1f] \x0303t\ufeffhethiny\x03 commented on pull request #14731 (Convert To WBFS Support): \x1f\x0302https://dolp.in/pr14731#pullrequestreview-4729277002\x03\x1f', 'type': 'notification'}
2026-07-18T20:45:50.555975	{'source': 'notifications', 'msg': '[\x1f\x0313dolphin-emu/dolphin\x03\x1f] \x0303t\ufeffhethiny\x03 commented on #14731 24b41d: \x1f\x0302https://dolp.in/pr14731#discussion_r3609163923\x03\x1f', 'type': 'notification'}
2026-07-18T20:44:52.063226	{'source': 'notifications', 'msg': '[\x1f\x0313dolphin-emu/dolphin\x03\x1f] \x0303t\ufeffhethiny\x03 commented on #14731 81f336: \x1f\x0302https://dolp.in/pr14731#discussion_r3609162555\x03\x1f', 'type': 'notification'}
2026-07-18T20:44:16.121387	{'source': 'notifications', 'msg': '[\x1f\x0313dolphin-emu/dolphin\x03\x1f] build for #14731 \x0304failed\x03 on builders [pr-win-dbg-x64]: \x1f\x0302https://dolphin.ci/#/builders/31/builds/10068\x03\x1f', 'type': 'notification'}
2026-07-18T20:43:14.355105	{'source': 'notifications', 'msg': '[\x1f\x0313dolphin-emu/dolphin\x03\x1f] build for #14731 \x0304failed\x03 on builders [pr-win-x64]: \x1f\x0302https://dolphin.ci/#/builders/2/builds/10061\x03\x1f', 'type': 'notification'}
2026-07-18T20:43:05.733799	{'source': 'notifications', 'msg': '[\x1f\x0313dolphin-emu/dolphin\x03\x1f] \x0303t\ufeffhethiny\x03 commented on #14731 81f336: \x1f\x0302https://dolp.in/pr14731#discussion_r3609159791\x03\x1f', 'type': 'notification'}
2026-07-18T20:42:09.116350	{'source': 'notifications', 'msg': '[\x1f\x0313dolphin-emu/dolphin\x03\x1f] build for #14731 \x0304failed\x03 on builders [pr-win-arm64]: \x1f\x0302https://dolphin.ci/#/builders/13/builds/10058\x03\x1f', 'type': 'notification'}
2026-07-18T20:36:10.807616	{'source': 'notifications', 'msg': '[\x1f\x0313dolphin-emu/dolphin\x03\x1f] \x0303L\ufeffordNyriox\x03 commented on #13025 (Core & UnitTests: Join declarations and assignments): \x1f\x0302https://dolp.in/pr13025#issuecomment-5012831867\x03\x1f', 'type': 'notification'}
2026-07-18T20:35:37.397861	{'source': 'notifications', 'msg': '[\x1f\x0313dolphin-emu/dolphin\x03\x1f] build for #14731 \x0304failed\x03 on builders [default]: \x1f\x0302<no url>\x03\x1f', 'type': 'notification'}
2026-07-18T20:35:06.404230	{'source': 'notifications', 'msg': '[\x1f\x0313dolphin-emu/dolphin\x03\x1f] \x0303t\ufeffhethiny\x03 synchronized pull request #14731: Convert To WBFS Support (\x0306master\x03...\x0306wbfs-conversion\x03): \x1f\x0302https://dolp.in/pr14731\x03\x1f', 'type': 'notification'}

Recent 'pull_request_fifoci_status' events

2026-07-18T21:47:05.337194	{'source': 'buildbot', 'repo': 'dolphin-emu/dolphin', 'hash': '24b41d58df2315831b74f76b95417f2739d02f9d', 'service': 'pr-fifoci-ogl-lin-mesa', 'pr': 14731, 'type': 'pull_request_fifoci_status'}
2026-07-18T21:34:41.214355	{'source': 'buildbot', 'repo': 'dolphin-emu/dolphin', 'hash': 'b1c77c53c795e6c6ee689b83e9b40ab77047d97b', 'service': 'pr-fifoci-ogl-lin-mesa', 'pr': 14731, 'type': 'pull_request_fifoci_status'}
2026-07-18T21:22:25.739993	{'source': 'buildbot', 'repo': 'dolphin-emu/dolphin', 'hash': '94c3e12bc861a18867fa45602a3e03df6a10a8bf', 'service': 'pr-fifoci-ogl-lin-mesa', 'pr': 13025, 'type': 'pull_request_fifoci_status'}
2026-07-18T21:22:21.566025	{'source': 'buildbot', 'repo': 'dolphin-emu/dolphin', 'hash': '24b41d58df2315831b74f76b95417f2739d02f9d', 'service': 'pr-fifoci-mvk-osx-m1', 'pr': 14731, 'type': 'pull_request_fifoci_status'}
2026-07-18T21:11:00.144032	{'source': 'buildbot', 'repo': 'dolphin-emu/dolphin', 'hash': '24b41d58df2315831b74f76b95417f2739d02f9d', 'service': 'pr-fifoci-mtl-osx-m1', 'pr': 14731, 'type': 'pull_request_fifoci_status'}
2026-07-18T21:04:43.935407	{'source': 'buildbot', 'repo': 'dolphin-emu/dolphin', 'hash': '24b41d58df2315831b74f76b95417f2739d02f9d', 'service': 'pr-fifoci-vk-lin-mesa', 'pr': 14731, 'type': 'pull_request_fifoci_status'}
2026-07-18T20:54:06.346153	{'source': 'buildbot', 'repo': 'dolphin-emu/dolphin', 'hash': '24b41d58df2315831b74f76b95417f2739d02f9d', 'service': 'pr-fifoci-sw-lin-mesa', 'pr': 14731, 'type': 'pull_request_fifoci_status'}
2026-07-18T20:47:06.148718	{'source': 'buildbot', 'repo': 'dolphin-emu/dolphin', 'hash': 'b1c77c53c795e6c6ee689b83e9b40ab77047d97b', 'service': 'pr-fifoci-vk-lin-mesa', 'pr': 14731, 'type': 'pull_request_fifoci_status'}
2026-07-18T20:34:37.987039	{'source': 'buildbot', 'repo': 'dolphin-emu/dolphin', 'hash': '94c3e12bc861a18867fa45602a3e03df6a10a8bf', 'service': 'pr-fifoci-vk-lin-mesa', 'pr': 13025, 'type': 'pull_request_fifoci_status'}
2026-07-18T20:30:37.190387	{'source': 'buildbot', 'repo': 'dolphin-emu/dolphin', 'hash': '94c3e12bc861a18867fa45602a3e03df6a10a8bf', 'service': 'pr-fifoci-mvk-osx-m1', 'pr': 13025, 'type': 'pull_request_fifoci_status'}
2026-07-18T20:18:46.513658	{'source': 'buildbot', 'repo': 'dolphin-emu/dolphin', 'hash': 'b1c77c53c795e6c6ee689b83e9b40ab77047d97b', 'service': 'pr-fifoci-sw-lin-mesa', 'pr': 14731, 'type': 'pull_request_fifoci_status'}
2026-07-18T20:17:00.050361	{'source': 'buildbot', 'repo': 'dolphin-emu/dolphin', 'hash': '94c3e12bc861a18867fa45602a3e03df6a10a8bf', 'service': 'pr-fifoci-mtl-osx-m1', 'pr': 13025, 'type': 'pull_request_fifoci_status'}
2026-07-18T20:11:50.592166	{'source': 'buildbot', 'repo': 'dolphin-emu/dolphin', 'hash': '94c3e12bc861a18867fa45602a3e03df6a10a8bf', 'service': 'pr-fifoci-sw-lin-mesa', 'pr': 13025, 'type': 'pull_request_fifoci_status'}
2026-07-18T03:16:03.661709	{'source': 'buildbot', 'repo': 'dolphin-emu/dolphin', 'hash': '81f336974c3eb2f93c05073734d2d7dc16309a6a', 'service': 'pr-fifoci-ogl-lin-mesa', 'pr': 14731, 'type': 'pull_request_fifoci_status'}
2026-07-18T03:03:36.546675	{'source': 'buildbot', 'repo': 'dolphin-emu/dolphin', 'hash': '81f336974c3eb2f93c05073734d2d7dc16309a6a', 'service': 'pr-fifoci-vk-lin-mesa', 'pr': 14731, 'type': 'pull_request_fifoci_status'}
2026-07-18T02:52:53.165579	{'source': 'buildbot', 'repo': 'dolphin-emu/dolphin', 'hash': '81f336974c3eb2f93c05073734d2d7dc16309a6a', 'service': 'pr-fifoci-sw-lin-mesa', 'pr': 14731, 'type': 'pull_request_fifoci_status'}
2026-07-17T15:06:00.937007	{'source': 'buildbot', 'repo': 'dolphin-emu/dolphin', 'hash': 'f0954b8bb060b7154f6be5d2326e8a2f7b6c46d5', 'service': 'pr-fifoci-mvk-osx-m1', 'pr': 14733, 'type': 'pull_request_fifoci_status'}
2026-07-17T14:54:16.741915	{'source': 'buildbot', 'repo': 'dolphin-emu/dolphin', 'hash': 'fb0cec70395fdaac5524c2881a7f1041c1e627df', 'service': 'pr-fifoci-mvk-osx-m1', 'pr': 14734, 'type': 'pull_request_fifoci_status'}
2026-07-17T14:42:35.099454	{'source': 'buildbot', 'repo': 'dolphin-emu/dolphin', 'hash': 'e58f57f6f3f7bc517887f5ef6d22741ff1af4900', 'service': 'pr-fifoci-mvk-osx-m1', 'pr': 14736, 'type': 'pull_request_fifoci_status'}
2026-07-17T14:30:50.067722	{'source': 'buildbot', 'repo': 'dolphin-emu/dolphin', 'hash': '41ffcdd2724d957b1b3383f2bea8272b8487a21b', 'service': 'pr-fifoci-mvk-osx-m1', 'pr': 14735, 'type': 'pull_request_fifoci_status'}
2026-07-17T14:18:38.183423	{'source': 'buildbot', 'repo': 'dolphin-emu/dolphin', 'hash': 'f0954b8bb060b7154f6be5d2326e8a2f7b6c46d5', 'service': 'pr-fifoci-mtl-osx-m1', 'pr': 14733, 'type': 'pull_request_fifoci_status'}
2026-07-17T13:55:29.833814	{'source': 'buildbot', 'repo': 'dolphin-emu/dolphin', 'hash': 'f0954b8bb060b7154f6be5d2326e8a2f7b6c46d5', 'service': 'pr-fifoci-ogl-lin-mesa', 'pr': 14733, 'type': 'pull_request_fifoci_status'}
2026-07-17T13:45:39.364876	{'source': 'buildbot', 'repo': 'dolphin-emu/dolphin', 'hash': 'fb0cec70395fdaac5524c2881a7f1041c1e627df', 'service': 'pr-fifoci-mtl-osx-m1', 'pr': 14734, 'type': 'pull_request_fifoci_status'}
2026-07-17T13:43:20.880769	{'source': 'buildbot', 'repo': 'dolphin-emu/dolphin', 'hash': 'fb0cec70395fdaac5524c2881a7f1041c1e627df', 'service': 'pr-fifoci-ogl-lin-mesa', 'pr': 14734, 'type': 'pull_request_fifoci_status'}
2026-07-17T13:31:12.812824	{'source': 'buildbot', 'repo': 'dolphin-emu/dolphin', 'hash': 'e58f57f6f3f7bc517887f5ef6d22741ff1af4900', 'service': 'pr-fifoci-ogl-lin-mesa', 'pr': 14736, 'type': 'pull_request_fifoci_status'}

Recent 'raw_bb_hook' events

2026-07-18T21:47:04.419175	{'source': 'webserver', 'raw': {'buildid': 180240, 'number': 8852, 'builderid': 10, 'buildrequestid': 180362, 'workerid': 5, 'masterid': 1, 'started_at': 1784410480, 'complete_at': 1784411224, 'locks_duration_s': 0, 'complete': True, 'state_string': 'build successful', 'results': 0, 'properties': {'baserev': ['d3b2943807dd0073f7767947466dd73cccfef319', 'Change'], 'scheduler': ['pr-fifoci-lin', 'Scheduler'], 'branch': ['refs/pull/14731/head', 'Build'], 'owners': [['Central (on behalf of: josjuice)'], 'Build'], 'got_revision': ['24b41d58df2315831b74f76b95417f2739d02f9d', 'GitNoBranch'], 'warnings-count': [0, 'WarningCountingShellCommand'], 'shortrev': ['24b41d', 'Trigger'], 'builderid': [10, 'Builder'], 'repository': ['', 'Build'], 'branchname': ['pr-14731', 'Trigger'], 'repo': ['dolphin-emu/dolphin', 'Trigger'], 'buildnumber': [8852, 'Build'], 'project': ['', 'Build'], 'headrev': ['24b41d58df2315831b74f76b95417f2739d02f9d', 'Trigger'], 'buildername': ['pr-fifoci-ogl-lin-mesa', 'Builder'], 'revision': ['24b41d58df2315831b74f76b95417f2739d02f9d', 'Build'], 'basedir': ['/var/lib/fifoci-worker/worker', 'Worker'], 'pr_id': [14731, 'Trigger'], 'workername': ['altair-fifoci', 'Worker'], 'codebase': ['', 'Build'], 'builddir': ['/var/lib/fifoci-worker/worker/pr-fifoci-ogl-lin-mesa', 'Worker']}, 'buildrequest': {'buildrequestid': 180362, 'buildsetid': 40830, 'builderid': 10, 'priority': 0, 'claimed': True, 'claimed_at': 1784410480, 'claimed_by_masterid': 1, 'complete': False, 'results': -1, 'submitted_at': 1784407267, 'complete_at': None, 'waited_for': False, 'properties': None}, 'buildset': {'bsid': 40830, 'external_idstring': None, 'reason': "The Triggerable scheduler named 'pr-fifoci-lin' triggered this build", 'submitted_at': 1784407267, 'complete': False, 'complete_at': None, 'results': -1, 'parent_buildid': 180230, 'parent_relationship': 'Triggered from', 'rebuilt_buildid': None, 'sourcestamps': [{'ssid': 12229, 'branch': 'refs/pull/14731/head', 'revision': '24b41d58df2315831b74f76b95417f2739d02f9d', 'project': '', 'repository': '', 'codebase': '', 'created_at': 1784407226, 'patch': None}]}, 'parentbuild': {'buildid': 180230, 'number': 10059, 'builderid': 27, 'buildrequestid': 180358, 'workerid': 10, 'masterid': 1, 'started_at': 1784407232, 'complete_at': 1784407267, 'locks_duration_s': 0, 'complete': True, 'state_string': 'build successful', 'results': 0, 'properties': {}}, 'parentbuilder': {'builderid': 27, 'name': 'pr-ubu-x64', 'masterids': [1], 'description': None, 'description_format': None, 'description_html': None, 'projectid': None, 'tags': []}, 'builder': {'builderid': 10, 'name': 'pr-fifoci-ogl-lin-mesa', 'masterids': [1], 'description': None, 'description_format': None, 'description_html': None, 'projectid': None, 'tags': []}, 'url': 'https://dolphin.ci/#/builders/10/builds/8852'}, 'type': 'raw_bb_hook'}
2026-07-18T21:34:40.335931	{'source': 'webserver', 'raw': {'buildid': 180240, 'number': 8852, 'builderid': 10, 'buildrequestid': 180362, 'workerid': 5, 'masterid': 1, 'started_at': 1784410480, 'complete_at': None, 'locks_duration_s': 0, 'complete': False, 'state_string': 'starting', 'results': None, 'properties': {'baserev': ['d3b2943807dd0073f7767947466dd73cccfef319', 'Change'], 'scheduler': ['pr-fifoci-lin', 'Scheduler'], 'branch': ['refs/pull/14731/head', 'Build'], 'shortrev': ['24b41d', 'Trigger'], 'builderid': [10, 'Builder'], 'repository': ['', 'Build'], 'branchname': ['pr-14731', 'Trigger'], 'repo': ['dolphin-emu/dolphin', 'Trigger'], 'buildnumber': [8852, 'Build'], 'project': ['', 'Build'], 'headrev': ['24b41d58df2315831b74f76b95417f2739d02f9d', 'Trigger'], 'buildername': ['pr-fifoci-ogl-lin-mesa', 'Builder'], 'revision': ['24b41d58df2315831b74f76b95417f2739d02f9d', 'Build'], 'pr_id': [14731, 'Trigger'], 'workername': ['altair-fifoci', 'Worker'], 'codebase': ['', 'Build']}, 'buildrequest': {'buildrequestid': 180362, 'buildsetid': 40830, 'builderid': 10, 'priority': 0, 'claimed': True, 'claimed_at': 1784410480, 'claimed_by_masterid': 1, 'complete': False, 'results': -1, 'submitted_at': 1784407267, 'complete_at': None, 'waited_for': False, 'properties': None}, 'buildset': {'bsid': 40830, 'external_idstring': None, 'reason': "The Triggerable scheduler named 'pr-fifoci-lin' triggered this build", 'submitted_at': 1784407267, 'complete': False, 'complete_at': None, 'results': -1, 'parent_buildid': 180230, 'parent_relationship': 'Triggered from', 'rebuilt_buildid': None, 'sourcestamps': [{'ssid': 12229, 'branch': 'refs/pull/14731/head', 'revision': '24b41d58df2315831b74f76b95417f2739d02f9d', 'project': '', 'repository': '', 'codebase': '', 'created_at': 1784407226, 'patch': None}]}, 'parentbuild': {'buildid': 180230, 'number': 10059, 'builderid': 27, 'buildrequestid': 180358, 'workerid': 10, 'masterid': 1, 'started_at': 1784407232, 'complete_at': 1784407267, 'locks_duration_s': 0, 'complete': True, 'state_string': 'build successful', 'results': 0, 'properties': {}}, 'parentbuilder': {'builderid': 27, 'name': 'pr-ubu-x64', 'masterids': [1], 'description': None, 'description_format': None, 'description_html': None, 'projectid': None, 'tags': []}, 'builder': {'builderid': 10, 'name': 'pr-fifoci-ogl-lin-mesa', 'masterids': [1], 'description': None, 'description_format': None, 'description_html': None, 'projectid': None, 'tags': []}, 'url': 'https://dolphin.ci/#/builders/10/builds/8852'}, 'type': 'raw_bb_hook'}
2026-07-18T21:34:40.247939	{'source': 'webserver', 'raw': {'buildid': 180239, 'number': 8851, 'builderid': 10, 'buildrequestid': 180345, 'workerid': 5, 'masterid': 1, 'started_at': 1784409732, 'complete_at': 1784410480, 'locks_duration_s': 0, 'complete': True, 'state_string': 'build successful', 'results': 0, 'properties': {'branchname': ['pr-14731', 'Trigger'], 'branch': ['refs/pull/14731/head', 'Build'], 'codebase': ['', 'Build'], 'got_revision': ['b1c77c53c795e6c6ee689b83e9b40ab77047d97b', 'GitNoBranch'], 'warnings-count': [22, 'WarningCountingShellCommand'], 'headrev': ['b1c77c53c795e6c6ee689b83e9b40ab77047d97b', 'Trigger'], 'pr_id': [14731, 'Trigger'], 'buildername': ['pr-fifoci-ogl-lin-mesa', 'Builder'], 'buildnumber': [8851, 'Build'], 'repository': ['', 'Build'], 'basedir': ['/var/lib/fifoci-worker/worker', 'Worker'], 'shortrev': ['b1c77c', 'Trigger'], 'scheduler': ['pr-fifoci-lin', 'Scheduler'], 'workername': ['altair-fifoci', 'Worker'], 'owners': [['Central (on behalf of: josjuice)'], 'Build'], 'baserev': ['d3b2943807dd0073f7767947466dd73cccfef319', 'Change'], 'repo': ['dolphin-emu/dolphin', 'Trigger'], 'builderid': [10, 'Builder'], 'revision': ['b1c77c53c795e6c6ee689b83e9b40ab77047d97b', 'Build'], 'project': ['', 'Build'], 'builddir': ['/var/lib/fifoci-worker/worker/pr-fifoci-ogl-lin-mesa', 'Worker']}, 'buildrequest': {'buildrequestid': 180345, 'buildsetid': 40826, 'builderid': 10, 'priority': 0, 'claimed': True, 'claimed_at': 1784409732, 'claimed_by_masterid': 1, 'complete': False, 'results': -1, 'submitted_at': 1784404456, 'complete_at': None, 'waited_for': False, 'properties': None}, 'buildset': {'bsid': 40826, 'external_idstring': None, 'reason': "The Triggerable scheduler named 'pr-fifoci-lin' triggered this build", 'submitted_at': 1784404456, 'complete': False, 'complete_at': None, 'results': -1, 'parent_buildid': 180205, 'parent_relationship': 'Triggered from', 'rebuilt_buildid': None, 'sourcestamps': [{'ssid': 12228, 'branch': 'refs/pull/14731/head', 'revision': 'b1c77c53c795e6c6ee689b83e9b40ab77047d97b', 'project': '', 'repository': '', 'codebase': '', 'created_at': 1784403839, 'patch': None}]}, 'parentbuild': {'buildid': 180205, 'number': 10058, 'builderid': 27, 'buildrequestid': 180338, 'workerid': 10, 'masterid': 1, 'started_at': 1784403933, 'complete_at': 1784404456, 'locks_duration_s': 0, 'complete': True, 'state_string': 'build successful', 'results': 0, 'properties': {}}, 'parentbuilder': {'builderid': 27, 'name': 'pr-ubu-x64', 'masterids': [1], 'description': None, 'description_format': None, 'description_html': None, 'projectid': None, 'tags': []}, 'builder': {'builderid': 10, 'name': 'pr-fifoci-ogl-lin-mesa', 'masterids': [1], 'description': None, 'description_format': None, 'description_html': None, 'projectid': None, 'tags': []}, 'url': 'https://dolphin.ci/#/builders/10/builds/8851'}, 'type': 'raw_bb_hook'}
2026-07-18T21:22:25.037126	{'source': 'webserver', 'raw': {'buildid': 180237, 'number': 8850, 'builderid': 10, 'buildrequestid': 180342, 'workerid': 5, 'masterid': 1, 'started_at': 1784408682, 'complete_at': 1784409732, 'locks_duration_s': 0, 'complete': True, 'state_string': 'build successful', 'results': 0, 'properties': {'warnings-count': [22, 'WarningCountingShellCommand'], 'baserev': ['415ec4de182034179143231e84c17dbcdf8be8aa', 'Change'], 'shortrev': ['94c3e1', 'Trigger'], 'repo': ['dolphin-emu/dolphin', 'Trigger'], 'buildername': ['pr-fifoci-ogl-lin-mesa', 'Builder'], 'workername': ['altair-fifoci', 'Worker'], 'branch': ['refs/pull/13025/head', 'Build'], 'repository': ['', 'Build'], 'project': ['', 'Build'], 'owners': [['Central (on behalf of: tygyh)'], 'Build'], 'builddir': ['/var/lib/fifoci-worker/worker/pr-fifoci-ogl-lin-mesa', 'Worker'], 'branchname': ['pr-13025', 'Trigger'], 'headrev': ['94c3e12bc861a18867fa45602a3e03df6a10a8bf', 'Trigger'], 'pr_id': [13025, 'Trigger'], 'scheduler': ['pr-fifoci-lin', 'Scheduler'], 'builderid': [10, 'Builder'], 'buildnumber': [8850, 'Build'], 'revision': ['94c3e12bc861a18867fa45602a3e03df6a10a8bf', 'Build'], 'codebase': ['', 'Build'], 'got_revision': ['94c3e12bc861a18867fa45602a3e03df6a10a8bf', 'GitNoBranch'], 'basedir': ['/var/lib/fifoci-worker/worker', 'Worker']}, 'buildrequest': {'buildrequestid': 180342, 'buildsetid': 40825, 'builderid': 10, 'priority': 0, 'claimed': True, 'claimed_at': 1784408682, 'claimed_by_masterid': 1, 'complete': False, 'results': -1, 'submitted_at': 1784403924, 'complete_at': None, 'waited_for': False, 'properties': None}, 'buildset': {'bsid': 40825, 'external_idstring': None, 'reason': "The Triggerable scheduler named 'pr-fifoci-lin' triggered this build", 'submitted_at': 1784403924, 'complete': False, 'complete_at': None, 'results': -1, 'parent_buildid': 180200, 'parent_relationship': 'Triggered from', 'rebuilt_buildid': None, 'sourcestamps': [{'ssid': 12227, 'branch': 'refs/pull/13025/head', 'revision': '94c3e12bc861a18867fa45602a3e03df6a10a8bf', 'project': '', 'repository': '', 'codebase': '', 'created_at': 1784403819, 'patch': None}]}, 'parentbuild': {'buildid': 180200, 'number': 10057, 'builderid': 27, 'buildrequestid': 180326, 'workerid': 10, 'masterid': 1, 'started_at': 1784403825, 'complete_at': 1784403925, 'locks_duration_s': 0, 'complete': True, 'state_string': 'build successful', 'results': 0, 'properties': {}}, 'parentbuilder': {'builderid': 27, 'name': 'pr-ubu-x64', 'masterids': [1], 'description': None, 'description_format': None, 'description_html': None, 'projectid': None, 'tags': []}, 'builder': {'builderid': 10, 'name': 'pr-fifoci-ogl-lin-mesa', 'masterids': [1], 'description': None, 'description_format': None, 'description_html': None, 'projectid': None, 'tags': []}, 'url': 'https://dolphin.ci/#/builders/10/builds/8850'}, 'type': 'raw_bb_hook'}
2026-07-18T21:22:20.629513	{'source': 'webserver', 'raw': {'buildid': 180238, 'number': 8613, 'builderid': 19, 'buildrequestid': 180365, 'workerid': 8, 'masterid': 1, 'started_at': 1784409059, 'complete_at': 1784409740, 'locks_duration_s': 0, 'complete': True, 'state_string': 'build successful', 'results': 0, 'properties': {'baserev': ['d3b2943807dd0073f7767947466dd73cccfef319', 'Change'], 'shortrev': ['24b41d', 'Trigger'], 'builderid': [19, 'Builder'], 'repository': ['', 'Build'], 'headrev': ['24b41d58df2315831b74f76b95417f2739d02f9d', 'Trigger'], 'scheduler': ['pr-fifoci-osx', 'Scheduler'], 'branch': ['refs/pull/14731/head', 'Build'], 'owners': [['Central (on behalf of: josjuice)'], 'Build'], 'got_revision': ['ca98b3030bcc70e67158ce899a5589aa2ec65d32', 'GitNoBranch'], 'pr_id': [14731, 'Trigger'], 'workername': ['osx-m1', 'Worker'], 'codebase': ['', 'Build'], 'builddir': ['/Users/administrator/buildbot-worker/osx_m1/pr-fifoci-mvk-osx-m1', 'Worker'], 'repo': ['dolphin-emu/dolphin', 'Trigger'], 'buildnumber': [8613, 'Build'], 'project': ['', 'Build'], 'basedir': ['/Users/administrator/buildbot-worker/osx_m1', 'Worker'], 'warnings-count': [120, 'WarningCountingShellCommand'], 'branchname': ['pr-14731', 'Trigger'], 'buildername': ['pr-fifoci-mvk-osx-m1', 'Builder'], 'revision': ['24b41d58df2315831b74f76b95417f2739d02f9d', 'Build']}, 'buildrequest': {'buildrequestid': 180365, 'buildsetid': 40831, 'builderid': 19, 'priority': 0, 'claimed': True, 'claimed_at': 1784409059, 'claimed_by_masterid': 1, 'complete': False, 'results': -1, 'submitted_at': 1784408388, 'complete_at': None, 'waited_for': False, 'properties': None}, 'buildset': {'bsid': 40831, 'external_idstring': None, 'reason': "The Triggerable scheduler named 'pr-fifoci-osx' triggered this build", 'submitted_at': 1784408388, 'complete': False, 'complete_at': None, 'results': -1, 'parent_buildid': 180229, 'parent_relationship': 'Triggered from', 'rebuilt_buildid': None, 'sourcestamps': [{'ssid': 12229, 'branch': 'refs/pull/14731/head', 'revision': '24b41d58df2315831b74f76b95417f2739d02f9d', 'project': '', 'repository': '', 'codebase': '', 'created_at': 1784407226, 'patch': None}]}, 'parentbuild': {'buildid': 180229, 'number': 10074, 'builderid': 7, 'buildrequestid': 180352, 'workerid': 8, 'masterid': 1, 'started_at': 1784407226, 'complete_at': 1784408388, 'locks_duration_s': 0, 'complete': True, 'state_string': 'build successful', 'results': 0, 'properties': {}}, 'parentbuilder': {'builderid': 7, 'name': 'pr-osx-universal', 'masterids': [1], 'description': None, 'description_format': None, 'description_html': None, 'projectid': None, 'tags': []}, 'builder': {'builderid': 19, 'name': 'pr-fifoci-mvk-osx-m1', 'masterids': [1], 'description': None, 'description_format': None, 'description_html': None, 'projectid': None, 'tags': []}, 'url': 'https://dolphin.ci/#/builders/19/builds/8613'}, 'type': 'raw_bb_hook'}
2026-07-18T21:22:12.691847	{'source': 'webserver', 'raw': {'buildid': 180239, 'number': 8851, 'builderid': 10, 'buildrequestid': 180345, 'workerid': 5, 'masterid': 1, 'started_at': 1784409732, 'complete_at': None, 'locks_duration_s': 0, 'complete': False, 'state_string': 'starting', 'results': None, 'properties': {'branchname': ['pr-14731', 'Trigger'], 'branch': ['refs/pull/14731/head', 'Build'], 'codebase': ['', 'Build'], 'headrev': ['b1c77c53c795e6c6ee689b83e9b40ab77047d97b', 'Trigger'], 'pr_id': [14731, 'Trigger'], 'buildername': ['pr-fifoci-ogl-lin-mesa', 'Builder'], 'buildnumber': [8851, 'Build'], 'repository': ['', 'Build'], 'shortrev': ['b1c77c', 'Trigger'], 'scheduler': ['pr-fifoci-lin', 'Scheduler'], 'workername': ['altair-fifoci', 'Worker'], 'owners': [['Central (on behalf of: josjuice)'], 'Build'], 'baserev': ['d3b2943807dd0073f7767947466dd73cccfef319', 'Change'], 'repo': ['dolphin-emu/dolphin', 'Trigger'], 'builderid': [10, 'Builder'], 'revision': ['b1c77c53c795e6c6ee689b83e9b40ab77047d97b', 'Build'], 'project': ['', 'Build']}, 'buildrequest': {'buildrequestid': 180345, 'buildsetid': 40826, 'builderid': 10, 'priority': 0, 'claimed': True, 'claimed_at': 1784409732, 'claimed_by_masterid': 1, 'complete': False, 'results': -1, 'submitted_at': 1784404456, 'complete_at': None, 'waited_for': False, 'properties': None}, 'buildset': {'bsid': 40826, 'external_idstring': None, 'reason': "The Triggerable scheduler named 'pr-fifoci-lin' triggered this build", 'submitted_at': 1784404456, 'complete': False, 'complete_at': None, 'results': -1, 'parent_buildid': 180205, 'parent_relationship': 'Triggered from', 'rebuilt_buildid': None, 'sourcestamps': [{'ssid': 12228, 'branch': 'refs/pull/14731/head', 'revision': 'b1c77c53c795e6c6ee689b83e9b40ab77047d97b', 'project': '', 'repository': '', 'codebase': '', 'created_at': 1784403839, 'patch': None}]}, 'parentbuild': {'buildid': 180205, 'number': 10058, 'builderid': 27, 'buildrequestid': 180338, 'workerid': 10, 'masterid': 1, 'started_at': 1784403933, 'complete_at': 1784404456, 'locks_duration_s': 0, 'complete': True, 'state_string': 'build successful', 'results': 0, 'properties': {}}, 'parentbuilder': {'builderid': 27, 'name': 'pr-ubu-x64', 'masterids': [1], 'description': None, 'description_format': None, 'description_html': None, 'projectid': None, 'tags': []}, 'builder': {'builderid': 10, 'name': 'pr-fifoci-ogl-lin-mesa', 'masterids': [1], 'description': None, 'description_format': None, 'description_html': None, 'projectid': None, 'tags': []}, 'url': 'https://dolphin.ci/#/builders/10/builds/8851'}, 'type': 'raw_bb_hook'}
2026-07-18T21:10:59.365597	{'source': 'webserver', 'raw': {'buildid': 180238, 'number': 8613, 'builderid': 19, 'buildrequestid': 180365, 'workerid': 8, 'masterid': 1, 'started_at': 1784409059, 'complete_at': None, 'locks_duration_s': 0, 'complete': False, 'state_string': 'starting', 'results': None, 'properties': {'baserev': ['d3b2943807dd0073f7767947466dd73cccfef319', 'Change'], 'shortrev': ['24b41d', 'Trigger'], 'builderid': [19, 'Builder'], 'repository': ['', 'Build'], 'headrev': ['24b41d58df2315831b74f76b95417f2739d02f9d', 'Trigger'], 'scheduler': ['pr-fifoci-osx', 'Scheduler'], 'branch': ['refs/pull/14731/head', 'Build'], 'pr_id': [14731, 'Trigger'], 'workername': ['osx-m1', 'Worker'], 'codebase': ['', 'Build'], 'repo': ['dolphin-emu/dolphin', 'Trigger'], 'buildnumber': [8613, 'Build'], 'project': ['', 'Build'], 'branchname': ['pr-14731', 'Trigger'], 'buildername': ['pr-fifoci-mvk-osx-m1', 'Builder'], 'revision': ['24b41d58df2315831b74f76b95417f2739d02f9d', 'Build']}, 'buildrequest': {'buildrequestid': 180365, 'buildsetid': 40831, 'builderid': 19, 'priority': 0, 'claimed': True, 'claimed_at': 1784409059, 'claimed_by_masterid': 1, 'complete': False, 'results': -1, 'submitted_at': 1784408388, 'complete_at': None, 'waited_for': False, 'properties': None}, 'buildset': {'bsid': 40831, 'external_idstring': None, 'reason': "The Triggerable scheduler named 'pr-fifoci-osx' triggered this build", 'submitted_at': 1784408388, 'complete': False, 'complete_at': None, 'results': -1, 'parent_buildid': 180229, 'parent_relationship': 'Triggered from', 'rebuilt_buildid': None, 'sourcestamps': [{'ssid': 12229, 'branch': 'refs/pull/14731/head', 'revision': '24b41d58df2315831b74f76b95417f2739d02f9d', 'project': '', 'repository': '', 'codebase': '', 'created_at': 1784407226, 'patch': None}]}, 'parentbuild': {'buildid': 180229, 'number': 10074, 'builderid': 7, 'buildrequestid': 180352, 'workerid': 8, 'masterid': 1, 'started_at': 1784407226, 'complete_at': 1784408388, 'locks_duration_s': 0, 'complete': True, 'state_string': 'build successful', 'results': 0, 'properties': {}}, 'parentbuilder': {'builderid': 7, 'name': 'pr-osx-universal', 'masterids': [1], 'description': None, 'description_format': None, 'description_html': None, 'projectid': None, 'tags': []}, 'builder': {'builderid': 19, 'name': 'pr-fifoci-mvk-osx-m1', 'masterids': [1], 'description': None, 'description_format': None, 'description_html': None, 'projectid': None, 'tags': []}, 'url': 'https://dolphin.ci/#/builders/19/builds/8613'}, 'type': 'raw_bb_hook'}
2026-07-18T21:10:59.207624	{'source': 'webserver', 'raw': {'buildid': 180236, 'number': 8615, 'builderid': 21, 'buildrequestid': 180366, 'workerid': 8, 'masterid': 1, 'started_at': 1784408388, 'complete_at': 1784409059, 'locks_duration_s': 0, 'complete': True, 'state_string': 'build successful', 'results': 0, 'properties': {'buildername': ['pr-fifoci-mtl-osx-m1', 'Builder'], 'codebase': ['', 'Build'], 'warnings-count': [120, 'WarningCountingShellCommand'], 'branchname': ['pr-14731', 'Trigger'], 'shortrev': ['24b41d', 'Trigger'], 'repo': ['dolphin-emu/dolphin', 'Trigger'], 'buildnumber': [8615, 'Build'], 'repository': ['', 'Build'], 'baserev': ['d3b2943807dd0073f7767947466dd73cccfef319', 'Change'], 'scheduler': ['pr-fifoci-osx', 'Scheduler'], 'branch': ['refs/pull/14731/head', 'Build'], 'owners': [['Central (on behalf of: josjuice)'], 'Build'], 'builddir': ['/Users/administrator/buildbot-worker/osx_m1/pr-fifoci-mtl-osx-m1', 'Worker'], 'pr_id': [14731, 'Trigger'], 'workername': ['osx-m1', 'Worker'], 'revision': ['24b41d58df2315831b74f76b95417f2739d02f9d', 'Build'], 'basedir': ['/Users/administrator/buildbot-worker/osx_m1', 'Worker'], 'headrev': ['24b41d58df2315831b74f76b95417f2739d02f9d', 'Trigger'], 'builderid': [21, 'Builder'], 'project': ['', 'Build'], 'got_revision': ['ca98b3030bcc70e67158ce899a5589aa2ec65d32', 'GitNoBranch']}, 'buildrequest': {'buildrequestid': 180366, 'buildsetid': 40831, 'builderid': 21, 'priority': 0, 'claimed': True, 'claimed_at': 1784408388, 'claimed_by_masterid': 1, 'complete': False, 'results': -1, 'submitted_at': 1784408388, 'complete_at': None, 'waited_for': False, 'properties': None}, 'buildset': {'bsid': 40831, 'external_idstring': None, 'reason': "The Triggerable scheduler named 'pr-fifoci-osx' triggered this build", 'submitted_at': 1784408388, 'complete': False, 'complete_at': None, 'results': -1, 'parent_buildid': 180229, 'parent_relationship': 'Triggered from', 'rebuilt_buildid': None, 'sourcestamps': [{'ssid': 12229, 'branch': 'refs/pull/14731/head', 'revision': '24b41d58df2315831b74f76b95417f2739d02f9d', 'project': '', 'repository': '', 'codebase': '', 'created_at': 1784407226, 'patch': None}]}, 'parentbuild': {'buildid': 180229, 'number': 10074, 'builderid': 7, 'buildrequestid': 180352, 'workerid': 8, 'masterid': 1, 'started_at': 1784407226, 'complete_at': 1784408388, 'locks_duration_s': 0, 'complete': True, 'state_string': 'build successful', 'results': 0, 'properties': {}}, 'parentbuilder': {'builderid': 7, 'name': 'pr-osx-universal', 'masterids': [1], 'description': None, 'description_format': None, 'description_html': None, 'projectid': None, 'tags': []}, 'builder': {'builderid': 21, 'name': 'pr-fifoci-mtl-osx-m1', 'masterids': [1], 'description': None, 'description_format': None, 'description_html': None, 'projectid': None, 'tags': []}, 'url': 'https://dolphin.ci/#/builders/21/builds/8615'}, 'type': 'raw_bb_hook'}
2026-07-18T21:04:56.421520	{'source': 'webserver', 'raw': {'buildid': 180237, 'number': 8850, 'builderid': 10, 'buildrequestid': 180342, 'workerid': 5, 'masterid': 1, 'started_at': 1784408682, 'complete_at': None, 'locks_duration_s': 0, 'complete': False, 'state_string': 'starting', 'results': None, 'properties': {'baserev': ['415ec4de182034179143231e84c17dbcdf8be8aa', 'Change'], 'shortrev': ['94c3e1', 'Trigger'], 'repo': ['dolphin-emu/dolphin', 'Trigger'], 'buildername': ['pr-fifoci-ogl-lin-mesa', 'Builder'], 'workername': ['altair-fifoci', 'Worker'], 'branch': ['refs/pull/13025/head', 'Build'], 'repository': ['', 'Build'], 'project': ['', 'Build'], 'owners': [['Central (on behalf of: tygyh)'], 'Build'], 'branchname': ['pr-13025', 'Trigger'], 'headrev': ['94c3e12bc861a18867fa45602a3e03df6a10a8bf', 'Trigger'], 'pr_id': [13025, 'Trigger'], 'scheduler': ['pr-fifoci-lin', 'Scheduler'], 'builderid': [10, 'Builder'], 'buildnumber': [8850, 'Build'], 'revision': ['94c3e12bc861a18867fa45602a3e03df6a10a8bf', 'Build'], 'codebase': ['', 'Build']}, 'buildrequest': {'buildrequestid': 180342, 'buildsetid': 40825, 'builderid': 10, 'priority': 0, 'claimed': True, 'claimed_at': 1784408682, 'claimed_by_masterid': 1, 'complete': False, 'results': -1, 'submitted_at': 1784403924, 'complete_at': None, 'waited_for': False, 'properties': None}, 'buildset': {'bsid': 40825, 'external_idstring': None, 'reason': "The Triggerable scheduler named 'pr-fifoci-lin' triggered this build", 'submitted_at': 1784403924, 'complete': False, 'complete_at': None, 'results': -1, 'parent_buildid': 180200, 'parent_relationship': 'Triggered from', 'rebuilt_buildid': None, 'sourcestamps': [{'ssid': 12227, 'branch': 'refs/pull/13025/head', 'revision': '94c3e12bc861a18867fa45602a3e03df6a10a8bf', 'project': '', 'repository': '', 'codebase': '', 'created_at': 1784403819, 'patch': None}]}, 'parentbuild': {'buildid': 180200, 'number': 10057, 'builderid': 27, 'buildrequestid': 180326, 'workerid': 10, 'masterid': 1, 'started_at': 1784403825, 'complete_at': 1784403925, 'locks_duration_s': 0, 'complete': True, 'state_string': 'build successful', 'results': 0, 'properties': {}}, 'parentbuilder': {'builderid': 27, 'name': 'pr-ubu-x64', 'masterids': [1], 'description': None, 'description_format': None, 'description_html': None, 'projectid': None, 'tags': []}, 'builder': {'builderid': 10, 'name': 'pr-fifoci-ogl-lin-mesa', 'masterids': [1], 'description': None, 'description_format': None, 'description_html': None, 'projectid': None, 'tags': []}, 'url': 'https://dolphin.ci/#/builders/10/builds/8850'}, 'type': 'raw_bb_hook'}
2026-07-18T21:04:42.992985	{'source': 'webserver', 'raw': {'buildid': 180235, 'number': 4841, 'builderid': 41, 'buildrequestid': 180364, 'workerid': 5, 'masterid': 1, 'started_at': 1784408045, 'complete_at': 1784408682, 'locks_duration_s': 0, 'complete': True, 'state_string': 'build successful', 'results': 0, 'properties': {'baserev': ['d3b2943807dd0073f7767947466dd73cccfef319', 'Change'], 'scheduler': ['pr-fifoci-lin', 'Scheduler'], 'branch': ['refs/pull/14731/head', 'Build'], 'headrev': ['24b41d58df2315831b74f76b95417f2739d02f9d', 'Trigger'], 'buildername': ['pr-fifoci-vk-lin-mesa', 'Builder'], 'revision': ['24b41d58df2315831b74f76b95417f2739d02f9d', 'Build'], 'got_revision': ['24b41d58df2315831b74f76b95417f2739d02f9d', 'GitNoBranch'], 'shortrev': ['24b41d', 'Trigger'], 'builderid': [41, 'Builder'], 'repository': ['', 'Build'], 'warnings-count': [0, 'WarningCountingShellCommand'], 'branchname': ['pr-14731', 'Trigger'], 'repo': ['dolphin-emu/dolphin', 'Trigger'], 'buildnumber': [4841, 'Build'], 'project': ['', 'Build'], 'basedir': ['/var/lib/fifoci-worker/worker', 'Worker'], 'owners': [['Central (on behalf of: josjuice)'], 'Build'], 'pr_id': [14731, 'Trigger'], 'workername': ['altair-fifoci', 'Worker'], 'codebase': ['', 'Build'], 'builddir': ['/var/lib/fifoci-worker/worker/pr-fifoci-vk-lin-mesa', 'Worker']}, 'buildrequest': {'buildrequestid': 180364, 'buildsetid': 40830, 'builderid': 41, 'priority': 0, 'claimed': True, 'claimed_at': 1784408045, 'claimed_by_masterid': 1, 'complete': False, 'results': -1, 'submitted_at': 1784407267, 'complete_at': None, 'waited_for': False, 'properties': None}, 'buildset': {'bsid': 40830, 'external_idstring': None, 'reason': "The Triggerable scheduler named 'pr-fifoci-lin' triggered this build", 'submitted_at': 1784407267, 'complete': False, 'complete_at': None, 'results': -1, 'parent_buildid': 180230, 'parent_relationship': 'Triggered from', 'rebuilt_buildid': None, 'sourcestamps': [{'ssid': 12229, 'branch': 'refs/pull/14731/head', 'revision': '24b41d58df2315831b74f76b95417f2739d02f9d', 'project': '', 'repository': '', 'codebase': '', 'created_at': 1784407226, 'patch': None}]}, 'parentbuild': {'buildid': 180230, 'number': 10059, 'builderid': 27, 'buildrequestid': 180358, 'workerid': 10, 'masterid': 1, 'started_at': 1784407232, 'complete_at': 1784407267, 'locks_duration_s': 0, 'complete': True, 'state_string': 'build successful', 'results': 0, 'properties': {}}, 'parentbuilder': {'builderid': 27, 'name': 'pr-ubu-x64', 'masterids': [1], 'description': None, 'description_format': None, 'description_html': None, 'projectid': None, 'tags': []}, 'builder': {'builderid': 41, 'name': 'pr-fifoci-vk-lin-mesa', 'masterids': [1], 'description': None, 'description_format': None, 'description_html': None, 'projectid': None, 'tags': []}, 'url': 'https://dolphin.ci/#/builders/41/builds/4841'}, 'type': 'raw_bb_hook'}
2026-07-18T20:59:48.493111	{'source': 'webserver', 'raw': {'buildid': 180236, 'number': 8615, 'builderid': 21, 'buildrequestid': 180366, 'workerid': 8, 'masterid': 1, 'started_at': 1784408388, 'complete_at': None, 'locks_duration_s': 0, 'complete': False, 'state_string': 'starting', 'results': None, 'properties': {'buildername': ['pr-fifoci-mtl-osx-m1', 'Builder'], 'codebase': ['', 'Build'], 'branchname': ['pr-14731', 'Trigger'], 'shortrev': ['24b41d', 'Trigger'], 'repo': ['dolphin-emu/dolphin', 'Trigger'], 'buildnumber': [8615, 'Build'], 'repository': ['', 'Build'], 'baserev': ['d3b2943807dd0073f7767947466dd73cccfef319', 'Change'], 'scheduler': ['pr-fifoci-osx', 'Scheduler'], 'branch': ['refs/pull/14731/head', 'Build'], 'pr_id': [14731, 'Trigger'], 'workername': ['osx-m1', 'Worker'], 'revision': ['24b41d58df2315831b74f76b95417f2739d02f9d', 'Build'], 'headrev': ['24b41d58df2315831b74f76b95417f2739d02f9d', 'Trigger'], 'builderid': [21, 'Builder'], 'project': ['', 'Build']}, 'buildrequest': {'buildrequestid': 180366, 'buildsetid': 40831, 'builderid': 21, 'priority': 0, 'claimed': True, 'claimed_at': 1784408388, 'claimed_by_masterid': 1, 'complete': False, 'results': -1, 'submitted_at': 1784408388, 'complete_at': None, 'waited_for': False, 'properties': None}, 'buildset': {'bsid': 40831, 'external_idstring': None, 'reason': "The Triggerable scheduler named 'pr-fifoci-osx' triggered this build", 'submitted_at': 1784408388, 'complete': False, 'complete_at': None, 'results': -1, 'parent_buildid': 180229, 'parent_relationship': 'Triggered from', 'rebuilt_buildid': None, 'sourcestamps': [{'ssid': 12229, 'branch': 'refs/pull/14731/head', 'revision': '24b41d58df2315831b74f76b95417f2739d02f9d', 'project': '', 'repository': '', 'codebase': '', 'created_at': 1784407226, 'patch': None}]}, 'parentbuild': {'buildid': 180229, 'number': 10074, 'builderid': 7, 'buildrequestid': 180352, 'workerid': 8, 'masterid': 1, 'started_at': 1784407226, 'complete_at': 1784408388, 'locks_duration_s': 0, 'complete': True, 'state_string': 'build successful', 'results': 0, 'properties': {}}, 'parentbuilder': {'builderid': 7, 'name': 'pr-osx-universal', 'masterids': [1], 'description': None, 'description_format': None, 'description_html': None, 'projectid': None, 'tags': []}, 'builder': {'builderid': 21, 'name': 'pr-fifoci-mtl-osx-m1', 'masterids': [1], 'description': None, 'description_format': None, 'description_html': None, 'projectid': None, 'tags': []}, 'url': 'https://dolphin.ci/#/builders/21/builds/8615'}, 'type': 'raw_bb_hook'}
2026-07-18T20:59:48.428371	{'source': 'webserver', 'raw': {'buildid': 180229, 'number': 10074, 'builderid': 7, 'buildrequestid': 180352, 'workerid': 8, 'masterid': 1, 'started_at': 1784407226, 'complete_at': 1784408388, 'locks_duration_s': 0, 'complete': True, 'state_string': 'build successful', 'results': 0, 'properties': {'got_revision': ['24b41d58df2315831b74f76b95417f2739d02f9d', 'GitNoBranch'], 'repo': ['dolphin-emu/dolphin', 'Change'], 'repository': ['', 'Build'], 'shortrev': ['24b41d', 'Change'], 'branchname': ['pr-14731', 'Change'], 'baserev': ['d3b2943807dd0073f7767947466dd73cccfef319', 'Change'], 'workername': ['osx-m1', 'Worker'], 'headrev': ['24b41d58df2315831b74f76b95417f2739d02f9d', 'Change'], 'scheduler': ['pr', 'Scheduler'], 'pr_id': [14731, 'Change'], 'buildername': ['pr-osx-universal', 'Builder'], 'builderid': [7, 'Builder'], 'branch': ['refs/pull/14731/head', 'Build'], 'revision': ['24b41d58df2315831b74f76b95417f2739d02f9d', 'Build'], 'buildnumber': [10074, 'Build'], 'codebase': ['', 'Build'], 'owners': [['Central (on behalf of: josjuice)'], 'Build'], 'basedir': ['/Users/administrator/buildbot-worker/osx_m1', 'Worker'], 'project': ['', 'Build'], 'builddir': ['/Users/administrator/buildbot-worker/osx_m1/pr-osx-universal', 'Worker']}, 'buildrequest': {'buildrequestid': 180352, 'buildsetid': 40829, 'builderid': 7, 'priority': 0, 'claimed': True, 'claimed_at': 1784407226, 'claimed_by_masterid': 1, 'complete': False, 'results': -1, 'submitted_at': 1784407226, 'complete_at': None, 'waited_for': False, 'properties': None}, 'buildset': {'bsid': 40829, 'external_idstring': None, 'reason': "The AnyBranchScheduler scheduler named 'pr' triggered this build", 'submitted_at': 1784407226, 'complete': False, 'complete_at': None, 'results': -1, 'parent_buildid': None, 'parent_relationship': None, 'rebuilt_buildid': None, 'sourcestamps': [{'ssid': 12229, 'branch': 'refs/pull/14731/head', 'revision': '24b41d58df2315831b74f76b95417f2739d02f9d', 'project': '', 'repository': '', 'codebase': '', 'created_at': 1784407226, 'patch': None}]}, 'parentbuild': None, 'parentbuilder': None, 'builder': {'builderid': 7, 'name': 'pr-osx-universal', 'masterids': [1], 'description': None, 'description_format': None, 'description_html': None, 'projectid': None, 'tags': []}, 'url': 'https://dolphin.ci/#/builders/7/builds/10074'}, 'type': 'raw_bb_hook'}
2026-07-18T20:54:05.507812	{'source': 'webserver', 'raw': {'buildid': 180235, 'number': 4841, 'builderid': 41, 'buildrequestid': 180364, 'workerid': 5, 'masterid': 1, 'started_at': 1784408045, 'complete_at': None, 'locks_duration_s': 0, 'complete': False, 'state_string': 'starting', 'results': None, 'properties': {'baserev': ['d3b2943807dd0073f7767947466dd73cccfef319', 'Change'], 'scheduler': ['pr-fifoci-lin', 'Scheduler'], 'branch': ['refs/pull/14731/head', 'Build'], 'headrev': ['24b41d58df2315831b74f76b95417f2739d02f9d', 'Trigger'], 'buildername': ['pr-fifoci-vk-lin-mesa', 'Builder'], 'revision': ['24b41d58df2315831b74f76b95417f2739d02f9d', 'Build'], 'shortrev': ['24b41d', 'Trigger'], 'builderid': [41, 'Builder'], 'repository': ['', 'Build'], 'branchname': ['pr-14731', 'Trigger'], 'repo': ['dolphin-emu/dolphin', 'Trigger'], 'buildnumber': [4841, 'Build'], 'project': ['', 'Build'], 'owners': [['Central (on behalf of: josjuice)'], 'Build'], 'pr_id': [14731, 'Trigger'], 'workername': ['altair-fifoci', 'Worker'], 'codebase': ['', 'Build']}, 'buildrequest': {'buildrequestid': 180364, 'buildsetid': 40830, 'builderid': 41, 'priority': 0, 'claimed': True, 'claimed_at': 1784408045, 'claimed_by_masterid': 1, 'complete': False, 'results': -1, 'submitted_at': 1784407267, 'complete_at': None, 'waited_for': False, 'properties': None}, 'buildset': {'bsid': 40830, 'external_idstring': None, 'reason': "The Triggerable scheduler named 'pr-fifoci-lin' triggered this build", 'submitted_at': 1784407267, 'complete': False, 'complete_at': None, 'results': -1, 'parent_buildid': 180230, 'parent_relationship': 'Triggered from', 'rebuilt_buildid': None, 'sourcestamps': [{'ssid': 12229, 'branch': 'refs/pull/14731/head', 'revision': '24b41d58df2315831b74f76b95417f2739d02f9d', 'project': '', 'repository': '', 'codebase': '', 'created_at': 1784407226, 'patch': None}]}, 'parentbuild': {'buildid': 180230, 'number': 10059, 'builderid': 27, 'buildrequestid': 180358, 'workerid': 10, 'masterid': 1, 'started_at': 1784407232, 'complete_at': 1784407267, 'locks_duration_s': 0, 'complete': True, 'state_string': 'build successful', 'results': 0, 'properties': {}}, 'parentbuilder': {'builderid': 27, 'name': 'pr-ubu-x64', 'masterids': [1], 'description': None, 'description_format': None, 'description_html': None, 'projectid': None, 'tags': []}, 'builder': {'builderid': 41, 'name': 'pr-fifoci-vk-lin-mesa', 'masterids': [1], 'description': None, 'description_format': None, 'description_html': None, 'projectid': None, 'tags': []}, 'url': 'https://dolphin.ci/#/builders/41/builds/4841'}, 'type': 'raw_bb_hook'}
2026-07-18T20:54:05.424168	{'source': 'webserver', 'raw': {'buildid': 180234, 'number': 8852, 'builderid': 35, 'buildrequestid': 180363, 'workerid': 5, 'masterid': 1, 'started_at': 1784407625, 'complete_at': 1784408045, 'locks_duration_s': 0, 'complete': True, 'state_string': 'build successful', 'results': 0, 'properties': {'pr_id': [14731, 'Trigger'], 'basedir': ['/var/lib/fifoci-worker/worker', 'Worker'], 'warnings-count': [0, 'WarningCountingShellCommand'], 'builddir': ['/var/lib/fifoci-worker/worker/pr-fifoci-sw-lin-mesa', 'Worker'], 'branchname': ['pr-14731', 'Trigger'], 'headrev': ['24b41d58df2315831b74f76b95417f2739d02f9d', 'Trigger'], 'scheduler': ['pr-fifoci-lin', 'Scheduler'], 'builderid': [35, 'Builder'], 'buildnumber': [8852, 'Build'], 'revision': ['24b41d58df2315831b74f76b95417f2739d02f9d', 'Build'], 'codebase': ['', 'Build'], 'baserev': ['d3b2943807dd0073f7767947466dd73cccfef319', 'Change'], 'shortrev': ['24b41d', 'Trigger'], 'repo': ['dolphin-emu/dolphin', 'Trigger'], 'buildername': ['pr-fifoci-sw-lin-mesa', 'Builder'], 'workername': ['altair-fifoci', 'Worker'], 'branch': ['refs/pull/14731/head', 'Build'], 'repository': ['', 'Build'], 'project': ['', 'Build'], 'owners': [['Central (on behalf of: josjuice)'], 'Build'], 'got_revision': ['24b41d58df2315831b74f76b95417f2739d02f9d', 'GitNoBranch']}, 'buildrequest': {'buildrequestid': 180363, 'buildsetid': 40830, 'builderid': 35, 'priority': 0, 'claimed': True, 'claimed_at': 1784407625, 'claimed_by_masterid': 1, 'complete': False, 'results': -1, 'submitted_at': 1784407267, 'complete_at': None, 'waited_for': False, 'properties': None}, 'buildset': {'bsid': 40830, 'external_idstring': None, 'reason': "The Triggerable scheduler named 'pr-fifoci-lin' triggered this build", 'submitted_at': 1784407267, 'complete': False, 'complete_at': None, 'results': -1, 'parent_buildid': 180230, 'parent_relationship': 'Triggered from', 'rebuilt_buildid': None, 'sourcestamps': [{'ssid': 12229, 'branch': 'refs/pull/14731/head', 'revision': '24b41d58df2315831b74f76b95417f2739d02f9d', 'project': '', 'repository': '', 'codebase': '', 'created_at': 1784407226, 'patch': None}]}, 'parentbuild': {'buildid': 180230, 'number': 10059, 'builderid': 27, 'buildrequestid': 180358, 'workerid': 10, 'masterid': 1, 'started_at': 1784407232, 'complete_at': 1784407267, 'locks_duration_s': 0, 'complete': True, 'state_string': 'build successful', 'results': 0, 'properties': {}}, 'parentbuilder': {'builderid': 27, 'name': 'pr-ubu-x64', 'masterids': [1], 'description': None, 'description_format': None, 'description_html': None, 'projectid': None, 'tags': []}, 'builder': {'builderid': 35, 'name': 'pr-fifoci-sw-lin-mesa', 'masterids': [1], 'description': None, 'description_format': None, 'description_html': None, 'projectid': None, 'tags': []}, 'url': 'https://dolphin.ci/#/builders/35/builds/8852'}, 'type': 'raw_bb_hook'}
2026-07-18T20:51:39.027815	{'source': 'webserver', 'raw': {'buildid': 180226, 'number': 10061, 'builderid': 22, 'buildrequestid': 180356, 'workerid': 12, 'masterid': 1, 'started_at': 1784407226, 'complete_at': 1784407898, 'locks_duration_s': 0, 'complete': True, 'state_string': 'build successful', 'results': 0, 'properties': {'got_revision': ['24b41d58df2315831b74f76b95417f2739d02f9d', 'GitNoBranch'], 'buildername': ['pr-android', 'Builder'], 'headrev': ['24b41d58df2315831b74f76b95417f2739d02f9d', 'Change'], 'shortrev': ['24b41d', 'Change'], 'scheduler': ['pr', 'Scheduler'], 'branchname': ['pr-14731', 'Change'], 'branch': ['refs/pull/14731/head', 'Build'], 'repository': ['', 'Build'], 'codebase': ['', 'Build'], 'project': ['', 'Build'], 'owners': [['Central (on behalf of: josjuice)'], 'Build'], 'baserev': ['d3b2943807dd0073f7767947466dd73cccfef319', 'Change'], 'workername': ['android', 'Worker'], 'pr_id': [14731, 'Change'], 'repo': ['dolphin-emu/dolphin', 'Change'], 'builderid': [22, 'Builder'], 'buildnumber': [10061, 'Build'], 'revision': ['24b41d58df2315831b74f76b95417f2739d02f9d', 'Build'], 'basedir': ['/buildbot', 'Worker'], 'builddir': ['/buildbot/pr-android', 'Worker']}, 'buildrequest': {'buildrequestid': 180356, 'buildsetid': 40829, 'builderid': 22, 'priority': 0, 'claimed': True, 'claimed_at': 1784407226, 'claimed_by_masterid': 1, 'complete': False, 'results': -1, 'submitted_at': 1784407226, 'complete_at': None, 'waited_for': False, 'properties': None}, 'buildset': {'bsid': 40829, 'external_idstring': None, 'reason': "The AnyBranchScheduler scheduler named 'pr' triggered this build", 'submitted_at': 1784407226, 'complete': False, 'complete_at': None, 'results': -1, 'parent_buildid': None, 'parent_relationship': None, 'rebuilt_buildid': None, 'sourcestamps': [{'ssid': 12229, 'branch': 'refs/pull/14731/head', 'revision': '24b41d58df2315831b74f76b95417f2739d02f9d', 'project': '', 'repository': '', 'codebase': '', 'created_at': 1784407226, 'patch': None}]}, 'parentbuild': None, 'parentbuilder': None, 'builder': {'builderid': 22, 'name': 'pr-android', 'masterids': [1], 'description': None, 'description_format': None, 'description_html': None, 'projectid': None, 'tags': []}, 'url': 'https://dolphin.ci/#/builders/22/builds/10061'}, 'type': 'raw_bb_hook'}
2026-07-18T20:47:05.378410	{'source': 'webserver', 'raw': {'buildid': 180234, 'number': 8852, 'builderid': 35, 'buildrequestid': 180363, 'workerid': 5, 'masterid': 1, 'started_at': 1784407625, 'complete_at': None, 'locks_duration_s': 0, 'complete': False, 'state_string': 'starting', 'results': None, 'properties': {'pr_id': [14731, 'Trigger'], 'branchname': ['pr-14731', 'Trigger'], 'headrev': ['24b41d58df2315831b74f76b95417f2739d02f9d', 'Trigger'], 'scheduler': ['pr-fifoci-lin', 'Scheduler'], 'builderid': [35, 'Builder'], 'buildnumber': [8852, 'Build'], 'revision': ['24b41d58df2315831b74f76b95417f2739d02f9d', 'Build'], 'codebase': ['', 'Build'], 'baserev': ['d3b2943807dd0073f7767947466dd73cccfef319', 'Change'], 'shortrev': ['24b41d', 'Trigger'], 'repo': ['dolphin-emu/dolphin', 'Trigger'], 'buildername': ['pr-fifoci-sw-lin-mesa', 'Builder'], 'workername': ['altair-fifoci', 'Worker'], 'branch': ['refs/pull/14731/head', 'Build'], 'repository': ['', 'Build'], 'project': ['', 'Build'], 'owners': [['Central (on behalf of: josjuice)'], 'Build']}, 'buildrequest': {'buildrequestid': 180363, 'buildsetid': 40830, 'builderid': 35, 'priority': 0, 'claimed': True, 'claimed_at': 1784407625, 'claimed_by_masterid': 1, 'complete': False, 'results': -1, 'submitted_at': 1784407267, 'complete_at': None, 'waited_for': False, 'properties': None}, 'buildset': {'bsid': 40830, 'external_idstring': None, 'reason': "The Triggerable scheduler named 'pr-fifoci-lin' triggered this build", 'submitted_at': 1784407267, 'complete': False, 'complete_at': None, 'results': -1, 'parent_buildid': 180230, 'parent_relationship': 'Triggered from', 'rebuilt_buildid': None, 'sourcestamps': [{'ssid': 12229, 'branch': 'refs/pull/14731/head', 'revision': '24b41d58df2315831b74f76b95417f2739d02f9d', 'project': '', 'repository': '', 'codebase': '', 'created_at': 1784407226, 'patch': None}]}, 'parentbuild': {'buildid': 180230, 'number': 10059, 'builderid': 27, 'buildrequestid': 180358, 'workerid': 10, 'masterid': 1, 'started_at': 1784407232, 'complete_at': 1784407267, 'locks_duration_s': 0, 'complete': True, 'state_string': 'build successful', 'results': 0, 'properties': {}}, 'parentbuilder': {'builderid': 27, 'name': 'pr-ubu-x64', 'masterids': [1], 'description': None, 'description_format': None, 'description_html': None, 'projectid': None, 'tags': []}, 'builder': {'builderid': 35, 'name': 'pr-fifoci-sw-lin-mesa', 'masterids': [1], 'description': None, 'description_format': None, 'description_html': None, 'projectid': None, 'tags': []}, 'url': 'https://dolphin.ci/#/builders/35/builds/8852'}, 'type': 'raw_bb_hook'}
2026-07-18T20:47:05.213090	{'source': 'webserver', 'raw': {'buildid': 180221, 'number': 4840, 'builderid': 41, 'buildrequestid': 180347, 'workerid': 5, 'masterid': 1, 'started_at': 1784406872, 'complete_at': 1784407625, 'locks_duration_s': 0, 'complete': True, 'state_string': 'build successful', 'results': 0, 'properties': {'branchname': ['pr-14731', 'Trigger'], 'headrev': ['b1c77c53c795e6c6ee689b83e9b40ab77047d97b', 'Trigger'], 'shortrev': ['b1c77c', 'Trigger'], 'scheduler': ['pr-fifoci-lin', 'Scheduler'], 'baserev': ['d3b2943807dd0073f7767947466dd73cccfef319', 'Change'], 'pr_id': [14731, 'Trigger'], 'basedir': ['/var/lib/fifoci-worker/worker', 'Worker'], 'repo': ['dolphin-emu/dolphin', 'Trigger'], 'buildername': ['pr-fifoci-vk-lin-mesa', 'Builder'], 'branch': ['refs/pull/14731/head', 'Build'], 'repository': ['', 'Build'], 'codebase': ['', 'Build'], 'builddir': ['/var/lib/fifoci-worker/worker/pr-fifoci-vk-lin-mesa', 'Worker'], 'warnings-count': [22, 'WarningCountingShellCommand'], 'builderid': [41, 'Builder'], 'buildnumber': [4840, 'Build'], 'revision': ['b1c77c53c795e6c6ee689b83e9b40ab77047d97b', 'Build'], 'owners': [['Central (on behalf of: josjuice)'], 'Build'], 'workername': ['altair-fifoci', 'Worker'], 'project': ['', 'Build'], 'got_revision': ['b1c77c53c795e6c6ee689b83e9b40ab77047d97b', 'GitNoBranch']}, 'buildrequest': {'buildrequestid': 180347, 'buildsetid': 40826, 'builderid': 41, 'priority': 0, 'claimed': True, 'claimed_at': 1784406872, 'claimed_by_masterid': 1, 'complete': False, 'results': -1, 'submitted_at': 1784404456, 'complete_at': None, 'waited_for': False, 'properties': None}, 'buildset': {'bsid': 40826, 'external_idstring': None, 'reason': "The Triggerable scheduler named 'pr-fifoci-lin' triggered this build", 'submitted_at': 1784404456, 'complete': False, 'complete_at': None, 'results': -1, 'parent_buildid': 180205, 'parent_relationship': 'Triggered from', 'rebuilt_buildid': None, 'sourcestamps': [{'ssid': 12228, 'branch': 'refs/pull/14731/head', 'revision': 'b1c77c53c795e6c6ee689b83e9b40ab77047d97b', 'project': '', 'repository': '', 'codebase': '', 'created_at': 1784403839, 'patch': None}]}, 'parentbuild': {'buildid': 180205, 'number': 10058, 'builderid': 27, 'buildrequestid': 180338, 'workerid': 10, 'masterid': 1, 'started_at': 1784403933, 'complete_at': 1784404456, 'locks_duration_s': 0, 'complete': True, 'state_string': 'build successful', 'results': 0, 'properties': {}}, 'parentbuilder': {'builderid': 27, 'name': 'pr-ubu-x64', 'masterids': [1], 'description': None, 'description_format': None, 'description_html': None, 'projectid': None, 'tags': []}, 'builder': {'builderid': 41, 'name': 'pr-fifoci-vk-lin-mesa', 'masterids': [1], 'description': None, 'description_format': None, 'description_html': None, 'projectid': None, 'tags': []}, 'url': 'https://dolphin.ci/#/builders/41/builds/4840'}, 'type': 'raw_bb_hook'}
2026-07-18T20:45:04.957653	{'source': 'webserver', 'raw': {'buildid': 180233, 'number': 10060, 'builderid': 1, 'buildrequestid': 180350, 'workerid': 9, 'masterid': 1, 'started_at': 1784407373, 'complete_at': 1784407504, 'locks_duration_s': 0, 'complete': True, 'state_string': 'build successful', 'results': 0, 'properties': {'repo': ['dolphin-emu/dolphin', 'Change'], 'buildername': ['pr-deb-dbg-x64', 'Builder'], 'revision': ['24b41d58df2315831b74f76b95417f2739d02f9d', 'Build'], 'headrev': ['24b41d58df2315831b74f76b95417f2739d02f9d', 'Change'], 'pr_id': [14731, 'Change'], 'builderid': [1, 'Builder'], 'repository': ['', 'Build'], 'basedir': ['/buildbot', 'Worker'], 'branchname': ['pr-14731', 'Change'], 'shortrev': ['24b41d', 'Change'], 'scheduler': ['pr', 'Scheduler'], 'branch': ['refs/pull/14731/head', 'Build'], 'owners': [['Central (on behalf of: josjuice)'], 'Build'], 'got_revision': ['24b41d58df2315831b74f76b95417f2739d02f9d', 'GitNoBranch'], 'baserev': ['d3b2943807dd0073f7767947466dd73cccfef319', 'Change'], 'workername': ['debian', 'Worker'], 'codebase': ['', 'Build'], 'builddir': ['/buildbot/pr-deb-dbg-x64', 'Worker'], 'warnings-count': [3, 'WarningCountingShellCommand'], 'buildnumber': [10060, 'Build'], 'project': ['', 'Build']}, 'buildrequest': {'buildrequestid': 180350, 'buildsetid': 40829, 'builderid': 1, 'priority': 0, 'claimed': True, 'claimed_at': 1784407373, 'claimed_by_masterid': 1, 'complete': False, 'results': -1, 'submitted_at': 1784407226, 'complete_at': None, 'waited_for': False, 'properties': None}, 'buildset': {'bsid': 40829, 'external_idstring': None, 'reason': "The AnyBranchScheduler scheduler named 'pr' triggered this build", 'submitted_at': 1784407226, 'complete': False, 'complete_at': None, 'results': -1, 'parent_buildid': None, 'parent_relationship': None, 'rebuilt_buildid': None, 'sourcestamps': [{'ssid': 12229, 'branch': 'refs/pull/14731/head', 'revision': '24b41d58df2315831b74f76b95417f2739d02f9d', 'project': '', 'repository': '', 'codebase': '', 'created_at': 1784407226, 'patch': None}]}, 'parentbuild': None, 'parentbuilder': None, 'builder': {'builderid': 1, 'name': 'pr-deb-dbg-x64', 'masterids': [1], 'description': None, 'description_format': None, 'description_html': None, 'projectid': None, 'tags': []}, 'url': 'https://dolphin.ci/#/builders/1/builds/10060'}, 'type': 'raw_bb_hook'}
2026-07-18T20:44:09.987318	{'source': 'webserver', 'raw': {'buildid': 180228, 'number': 5204, 'builderid': 43, 'buildrequestid': 180360, 'workerid': 13, 'masterid': 1, 'started_at': 1784407226, 'complete_at': 1784407449, 'locks_duration_s': 0, 'complete': True, 'state_string': 'build successful', 'results': 0, 'properties': {'fm_build_url': ['https://flat-manager.dolphin-emu.org/api/v1/build/11634', 'SetPropertyFromCommand Step'], 'branchname': ['pr-14731', 'Change'], 'headrev': ['24b41d58df2315831b74f76b95417f2739d02f9d', 'Change'], 'shortrev': ['24b41d', 'Change'], 'pr_id': [14731, 'Change'], 'repo': ['dolphin-emu/dolphin', 'Change'], 'scheduler': ['pr', 'Scheduler'], 'baserev': ['d3b2943807dd0073f7767947466dd73cccfef319', 'Change'], 'codebase': ['', 'Build'], 'project': ['', 'Build'], 'buildername': ['pr-flatpak-x64', 'Builder'], 'builderid': [43, 'Builder'], 'workername': ['altair-flatpak', 'Worker'], 'branch': ['refs/pull/14731/head', 'Build'], 'revision': ['24b41d58df2315831b74f76b95417f2739d02f9d', 'Build'], 'repository': ['', 'Build'], 'buildnumber': [5204, 'Build'], 'owners': [['Central (on behalf of: josjuice)'], 'Build'], 'basedir': ['/var/lib/flatpak-worker/worker', 'Worker'], 'got_revision': ['24b41d58df2315831b74f76b95417f2739d02f9d', 'GitNoBranch'], 'builddir': ['/var/lib/flatpak-worker/worker/pr-flatpak-x64', 'Worker']}, 'buildrequest': {'buildrequestid': 180360, 'buildsetid': 40829, 'builderid': 43, 'priority': 0, 'claimed': True, 'claimed_at': 1784407226, 'claimed_by_masterid': 1, 'complete': False, 'results': -1, 'submitted_at': 1784407226, 'complete_at': None, 'waited_for': False, 'properties': None}, 'buildset': {'bsid': 40829, 'external_idstring': None, 'reason': "The AnyBranchScheduler scheduler named 'pr' triggered this build", 'submitted_at': 1784407226, 'complete': False, 'complete_at': None, 'results': -1, 'parent_buildid': None, 'parent_relationship': None, 'rebuilt_buildid': None, 'sourcestamps': [{'ssid': 12229, 'branch': 'refs/pull/14731/head', 'revision': '24b41d58df2315831b74f76b95417f2739d02f9d', 'project': '', 'repository': '', 'codebase': '', 'created_at': 1784407226, 'patch': None}]}, 'parentbuild': None, 'parentbuilder': None, 'builder': {'builderid': 43, 'name': 'pr-flatpak-x64', 'masterids': [1], 'description': None, 'description_format': None, 'description_html': None, 'projectid': None, 'tags': []}, 'url': 'https://dolphin.ci/#/builders/43/builds/5204'}, 'type': 'raw_bb_hook'}
2026-07-18T20:43:45.951671	{'source': 'webserver', 'raw': {'buildid': 180224, 'number': 5148, 'builderid': 44, 'buildrequestid': 180361, 'workerid': 14, 'masterid': 1, 'started_at': 1784407226, 'complete_at': 1784407425, 'locks_duration_s': 0, 'complete': True, 'state_string': 'build successful', 'results': 0, 'properties': {'basedir': ['/var/lib/flatpak-worker/worker', 'Worker'], 'builddir': ['/var/lib/flatpak-worker/worker/pr-flatpak-arm64', 'Worker'], 'got_revision': ['24b41d58df2315831b74f76b95417f2739d02f9d', 'GitNoBranch'], 'branchname': ['pr-14731', 'Change'], 'buildnumber': [5148, 'Build'], 'pr_id': [14731, 'Change'], 'repo': ['dolphin-emu/dolphin', 'Change'], 'scheduler': ['pr', 'Scheduler'], 'buildername': ['pr-flatpak-arm64', 'Builder'], 'fm_build_url': ['https://flat-manager.dolphin-emu.org/api/v1/build/11633', 'SetPropertyFromCommand Step'], 'baserev': ['d3b2943807dd0073f7767947466dd73cccfef319', 'Change'], 'headrev': ['24b41d58df2315831b74f76b95417f2739d02f9d', 'Change'], 'shortrev': ['24b41d', 'Change'], 'builderid': [44, 'Builder'], 'branch': ['refs/pull/14731/head', 'Build'], 'workername': ['deneb-flatpak', 'Worker'], 'revision': ['24b41d58df2315831b74f76b95417f2739d02f9d', 'Build'], 'repository': ['', 'Build'], 'codebase': ['', 'Build'], 'project': ['', 'Build'], 'owners': [['Central (on behalf of: josjuice)'], 'Build']}, 'buildrequest': {'buildrequestid': 180361, 'buildsetid': 40829, 'builderid': 44, 'priority': 0, 'claimed': True, 'claimed_at': 1784407226, 'claimed_by_masterid': 1, 'complete': False, 'results': -1, 'submitted_at': 1784407226, 'complete_at': None, 'waited_for': False, 'properties': None}, 'buildset': {'bsid': 40829, 'external_idstring': None, 'reason': "The AnyBranchScheduler scheduler named 'pr' triggered this build", 'submitted_at': 1784407226, 'complete': False, 'complete_at': None, 'results': -1, 'parent_buildid': None, 'parent_relationship': None, 'rebuilt_buildid': None, 'sourcestamps': [{'ssid': 12229, 'branch': 'refs/pull/14731/head', 'revision': '24b41d58df2315831b74f76b95417f2739d02f9d', 'project': '', 'repository': '', 'codebase': '', 'created_at': 1784407226, 'patch': None}]}, 'parentbuild': None, 'parentbuilder': None, 'builder': {'builderid': 44, 'name': 'pr-flatpak-arm64', 'masterids': [1], 'description': None, 'description_format': None, 'description_html': None, 'projectid': None, 'tags': []}, 'url': 'https://dolphin.ci/#/builders/44/builds/5148'}, 'type': 'raw_bb_hook'}
2026-07-18T20:43:45.736920	{'source': 'webserver', 'raw': {'buildid': 180232, 'number': 10068, 'builderid': 31, 'buildrequestid': 180359, 'workerid': 4, 'masterid': 1, 'started_at': 1784407363, 'complete_at': 1784407425, 'locks_duration_s': 0, 'complete': True, 'state_string': 'failed build (failure)', 'results': 2, 'properties': {'branchname': ['pr-14731', 'Change'], 'headrev': ['24b41d58df2315831b74f76b95417f2739d02f9d', 'Change'], 'repo': ['dolphin-emu/dolphin', 'Change'], 'buildername': ['pr-win-dbg-x64', 'Builder'], 'buildnumber': [10068, 'Build'], 'revision': ['24b41d58df2315831b74f76b95417f2739d02f9d', 'Build'], 'project': ['', 'Build'], 'owners': [['Central (on behalf of: josjuice)'], 'Build'], 'builddir': ['c:\\buildbot\\pr-win-dbg-x64', 'Worker'], 'got_revision': ['24b41d58df2315831b74f76b95417f2739d02f9d', 'GitNoBranch'], 'shortrev': ['24b41d', 'Change'], 'builderid': [31, 'Builder'], 'repository': ['', 'Build'], 'pr_id': [14731, 'Change'], 'workername': ['windows', 'Worker'], 'codebase': ['', 'Build'], 'warnings-count': [0, 'WarningCountingShellCommand'], 'baserev': ['d3b2943807dd0073f7767947466dd73cccfef319', 'Change'], 'scheduler': ['pr', 'Scheduler'], 'branch': ['refs/pull/14731/head', 'Build'], 'basedir': ['c:\\buildbot', 'Worker']}, 'buildrequest': {'buildrequestid': 180359, 'buildsetid': 40829, 'builderid': 31, 'priority': 0, 'claimed': True, 'claimed_at': 1784407363, 'claimed_by_masterid': 1, 'complete': False, 'results': -1, 'submitted_at': 1784407226, 'complete_at': None, 'waited_for': False, 'properties': None}, 'buildset': {'bsid': 40829, 'external_idstring': None, 'reason': "The AnyBranchScheduler scheduler named 'pr' triggered this build", 'submitted_at': 1784407226, 'complete': False, 'complete_at': None, 'results': -1, 'parent_buildid': None, 'parent_relationship': None, 'rebuilt_buildid': None, 'sourcestamps': [{'ssid': 12229, 'branch': 'refs/pull/14731/head', 'revision': '24b41d58df2315831b74f76b95417f2739d02f9d', 'project': '', 'repository': '', 'codebase': '', 'created_at': 1784407226, 'patch': None}]}, 'parentbuild': None, 'parentbuilder': None, 'builder': {'builderid': 31, 'name': 'pr-win-dbg-x64', 'masterids': [1], 'description': None, 'description_format': None, 'description_html': None, 'projectid': None, 'tags': []}, 'url': 'https://dolphin.ci/#/builders/31/builds/10068'}, 'type': 'raw_bb_hook'}
2026-07-18T20:42:53.927589	{'source': 'webserver', 'raw': {'buildid': 180233, 'number': 10060, 'builderid': 1, 'buildrequestid': 180350, 'workerid': 9, 'masterid': 1, 'started_at': 1784407373, 'complete_at': None, 'locks_duration_s': 0, 'complete': False, 'state_string': 'starting', 'results': None, 'properties': {'repo': ['dolphin-emu/dolphin', 'Change'], 'buildername': ['pr-deb-dbg-x64', 'Builder'], 'revision': ['24b41d58df2315831b74f76b95417f2739d02f9d', 'Build'], 'headrev': ['24b41d58df2315831b74f76b95417f2739d02f9d', 'Change'], 'pr_id': [14731, 'Change'], 'builderid': [1, 'Builder'], 'repository': ['', 'Build'], 'branchname': ['pr-14731', 'Change'], 'shortrev': ['24b41d', 'Change'], 'scheduler': ['pr', 'Scheduler'], 'branch': ['refs/pull/14731/head', 'Build'], 'owners': [['Central (on behalf of: josjuice)'], 'Build'], 'baserev': ['d3b2943807dd0073f7767947466dd73cccfef319', 'Change'], 'workername': ['debian', 'Worker'], 'codebase': ['', 'Build'], 'buildnumber': [10060, 'Build'], 'project': ['', 'Build']}, 'buildrequest': {'buildrequestid': 180350, 'buildsetid': 40829, 'builderid': 1, 'priority': 0, 'claimed': True, 'claimed_at': 1784407373, 'claimed_by_masterid': 1, 'complete': False, 'results': -1, 'submitted_at': 1784407226, 'complete_at': None, 'waited_for': False, 'properties': None}, 'buildset': {'bsid': 40829, 'external_idstring': None, 'reason': "The AnyBranchScheduler scheduler named 'pr' triggered this build", 'submitted_at': 1784407226, 'complete': False, 'complete_at': None, 'results': -1, 'parent_buildid': None, 'parent_relationship': None, 'rebuilt_buildid': None, 'sourcestamps': [{'ssid': 12229, 'branch': 'refs/pull/14731/head', 'revision': '24b41d58df2315831b74f76b95417f2739d02f9d', 'project': '', 'repository': '', 'codebase': '', 'created_at': 1784407226, 'patch': None}]}, 'parentbuild': None, 'parentbuilder': None, 'builder': {'builderid': 1, 'name': 'pr-deb-dbg-x64', 'masterids': [1], 'description': None, 'description_format': None, 'description_html': None, 'projectid': None, 'tags': []}, 'url': 'https://dolphin.ci/#/builders/1/builds/10060'}, 'type': 'raw_bb_hook'}
2026-07-18T20:42:53.783999	{'source': 'webserver', 'raw': {'buildid': 180227, 'number': 10058, 'builderid': 26, 'buildrequestid': 180357, 'workerid': 9, 'masterid': 1, 'started_at': 1784407226, 'complete_at': 1784407373, 'locks_duration_s': 0, 'complete': True, 'state_string': 'build successful', 'results': 0, 'properties': {'basedir': ['/buildbot', 'Worker'], 'warnings-count': [3, 'WarningCountingShellCommand'], 'got_revision': ['24b41d58df2315831b74f76b95417f2739d02f9d', 'GitNoBranch'], 'baserev': ['d3b2943807dd0073f7767947466dd73cccfef319', 'Change'], 'branchname': ['pr-14731', 'Change'], 'project': ['', 'Build'], 'headrev': ['24b41d58df2315831b74f76b95417f2739d02f9d', 'Change'], 'shortrev': ['24b41d', 'Change'], 'repo': ['dolphin-emu/dolphin', 'Change'], 'scheduler': ['pr', 'Scheduler'], 'buildername': ['pr-deb-x64', 'Builder'], 'pr_id': [14731, 'Change'], 'builderid': [26, 'Builder'], 'workername': ['debian', 'Worker'], 'buildnumber': [10058, 'Build'], 'revision': ['24b41d58df2315831b74f76b95417f2739d02f9d', 'Build'], 'repository': ['', 'Build'], 'branch': ['refs/pull/14731/head', 'Build'], 'codebase': ['', 'Build'], 'owners': [['Central (on behalf of: josjuice)'], 'Build'], 'builddir': ['/buildbot/pr-deb-x64', 'Worker']}, 'buildrequest': {'buildrequestid': 180357, 'buildsetid': 40829, 'builderid': 26, 'priority': 0, 'claimed': True, 'claimed_at': 1784407226, 'claimed_by_masterid': 1, 'complete': False, 'results': -1, 'submitted_at': 1784407226, 'complete_at': None, 'waited_for': False, 'properties': None}, 'buildset': {'bsid': 40829, 'external_idstring': None, 'reason': "The AnyBranchScheduler scheduler named 'pr' triggered this build", 'submitted_at': 1784407226, 'complete': False, 'complete_at': None, 'results': -1, 'parent_buildid': None, 'parent_relationship': None, 'rebuilt_buildid': None, 'sourcestamps': [{'ssid': 12229, 'branch': 'refs/pull/14731/head', 'revision': '24b41d58df2315831b74f76b95417f2739d02f9d', 'project': '', 'repository': '', 'codebase': '', 'created_at': 1784407226, 'patch': None}]}, 'parentbuild': None, 'parentbuilder': None, 'builder': {'builderid': 26, 'name': 'pr-deb-x64', 'masterids': [1], 'description': None, 'description_format': None, 'description_html': None, 'projectid': None, 'tags': []}, 'url': 'https://dolphin.ci/#/builders/26/builds/10058'}, 'type': 'raw_bb_hook'}
2026-07-18T20:42:43.905757	{'source': 'webserver', 'raw': {'buildid': 180232, 'number': 10068, 'builderid': 31, 'buildrequestid': 180359, 'workerid': 4, 'masterid': 1, 'started_at': 1784407363, 'complete_at': None, 'locks_duration_s': 0, 'complete': False, 'state_string': 'starting', 'results': None, 'properties': {'branchname': ['pr-14731', 'Change'], 'headrev': ['24b41d58df2315831b74f76b95417f2739d02f9d', 'Change'], 'repo': ['dolphin-emu/dolphin', 'Change'], 'buildername': ['pr-win-dbg-x64', 'Builder'], 'buildnumber': [10068, 'Build'], 'revision': ['24b41d58df2315831b74f76b95417f2739d02f9d', 'Build'], 'project': ['', 'Build'], 'shortrev': ['24b41d', 'Change'], 'builderid': [31, 'Builder'], 'repository': ['', 'Build'], 'pr_id': [14731, 'Change'], 'workername': ['windows', 'Worker'], 'codebase': ['', 'Build'], 'baserev': ['d3b2943807dd0073f7767947466dd73cccfef319', 'Change'], 'scheduler': ['pr', 'Scheduler'], 'branch': ['refs/pull/14731/head', 'Build']}, 'buildrequest': {'buildrequestid': 180359, 'buildsetid': 40829, 'builderid': 31, 'priority': 0, 'claimed': True, 'claimed_at': 1784407363, 'claimed_by_masterid': 1, 'complete': False, 'results': -1, 'submitted_at': 1784407226, 'complete_at': None, 'waited_for': False, 'properties': None}, 'buildset': {'bsid': 40829, 'external_idstring': None, 'reason': "The AnyBranchScheduler scheduler named 'pr' triggered this build", 'submitted_at': 1784407226, 'complete': False, 'complete_at': None, 'results': -1, 'parent_buildid': None, 'parent_relationship': None, 'rebuilt_buildid': None, 'sourcestamps': [{'ssid': 12229, 'branch': 'refs/pull/14731/head', 'revision': '24b41d58df2315831b74f76b95417f2739d02f9d', 'project': '', 'repository': '', 'codebase': '', 'created_at': 1784407226, 'patch': None}]}, 'parentbuild': None, 'parentbuilder': None, 'builder': {'builderid': 31, 'name': 'pr-win-dbg-x64', 'masterids': [1], 'description': None, 'description_format': None, 'description_html': None, 'projectid': None, 'tags': []}, 'url': 'https://dolphin.ci/#/builders/31/builds/10068'}, 'type': 'raw_bb_hook'}
2026-07-18T20:42:43.746592	{'source': 'webserver', 'raw': {'buildid': 180231, 'number': 10061, 'builderid': 2, 'buildrequestid': 180351, 'workerid': 4, 'masterid': 1, 'started_at': 1784407298, 'complete_at': 1784407363, 'locks_duration_s': 0, 'complete': True, 'state_string': 'failed build (failure)', 'results': 2, 'properties': {'baserev': ['d3b2943807dd0073f7767947466dd73cccfef319', 'Change'], 'headrev': ['24b41d58df2315831b74f76b95417f2739d02f9d', 'Change'], 'scheduler': ['pr', 'Scheduler'], 'buildername': ['pr-win-x64', 'Builder'], 'branch': ['refs/pull/14731/head', 'Build'], 'revision': ['24b41d58df2315831b74f76b95417f2739d02f9d', 'Build'], 'owners': [['Central (on behalf of: josjuice)'], 'Build'], 'basedir': ['c:\\buildbot', 'Worker'], 'got_revision': ['24b41d58df2315831b74f76b95417f2739d02f9d', 'GitNoBranch'], 'warnings-count': [0, 'WarningCountingShellCommand'], 'pr_id': [14731, 'Change'], 'workername': ['windows', 'Worker'], 'codebase': ['', 'Build'], 'builddir': ['c:\\buildbot\\pr-win-x64', 'Worker'], 'branchname': ['pr-14731', 'Change'], 'repo': ['dolphin-emu/dolphin', 'Change'], 'buildnumber': [10061, 'Build'], 'project': ['', 'Build'], 'shortrev': ['24b41d', 'Change'], 'builderid': [2, 'Builder'], 'repository': ['', 'Build']}, 'buildrequest': {'buildrequestid': 180351, 'buildsetid': 40829, 'builderid': 2, 'priority': 0, 'claimed': True, 'claimed_at': 1784407298, 'claimed_by_masterid': 1, 'complete': False, 'results': -1, 'submitted_at': 1784407226, 'complete_at': None, 'waited_for': False, 'properties': None}, 'buildset': {'bsid': 40829, 'external_idstring': None, 'reason': "The AnyBranchScheduler scheduler named 'pr' triggered this build", 'submitted_at': 1784407226, 'complete': False, 'complete_at': None, 'results': -1, 'parent_buildid': None, 'parent_relationship': None, 'rebuilt_buildid': None, 'sourcestamps': [{'ssid': 12229, 'branch': 'refs/pull/14731/head', 'revision': '24b41d58df2315831b74f76b95417f2739d02f9d', 'project': '', 'repository': '', 'codebase': '', 'created_at': 1784407226, 'patch': None}]}, 'parentbuild': None, 'parentbuilder': None, 'builder': {'builderid': 2, 'name': 'pr-win-x64', 'masterids': [1], 'description': None, 'description_format': None, 'description_html': None, 'projectid': None, 'tags': []}, 'url': 'https://dolphin.ci/#/builders/2/builds/10061'}, 'type': 'raw_bb_hook'}

Recent 'raw_gh_hook' events

2026-07-18T23:41:40.251704	{'source': 'webserver', 'gh_type': 'issue_comment', 'raw': {'action': 'created', 'issue': {'url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/14731', 'repository_url': 'https://api.github.com/repos/dolphin-emu/dolphin', 'labels_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/14731/labels{/name}', 'comments_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/14731/comments', 'events_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/14731/events', 'html_url': 'https://github.com/dolphin-emu/dolphin/pull/14731', 'id': 4888393904, 'node_id': 'PR_kwDOALCn2M7x0I-2', 'number': 14731, 'title': 'Convert To WBFS Support', 'user': {'login': 'thethiny', 'id': 6018214, 'node_id': 'MDQ6VXNlcjYwMTgyMTQ=', 'avatar_url': 'https://avatars.githubusercontent.com/u/6018214?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/thethiny', 'html_url': 'https://github.com/thethiny', 'followers_url': 'https://api.github.com/users/thethiny/followers', 'following_url': 'https://api.github.com/users/thethiny/following{/other_user}', 'gists_url': 'https://api.github.com/users/thethiny/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/thethiny/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/thethiny/subscriptions', 'organizations_url': 'https://api.github.com/users/thethiny/orgs', 'repos_url': 'https://api.github.com/users/thethiny/repos', 'events_url': 'https://api.github.com/users/thethiny/events{/privacy}', 'received_events_url': 'https://api.github.com/users/thethiny/received_events', 'type': 'User', 'user_view_type': 'public', 'site_admin': False}, 'labels': [], 'state': 'open', 'locked': False, 'assignees': [], 'milestone': None, 'comments': 43, 'created_at': '2026-07-15T01:16:25Z', 'updated_at': '2026-07-18T23:41:38Z', 'closed_at': None, 'assignee': None, 'author_association': 'NONE', 'issue_field_values': [], 'type': None, 'active_lock_reason': None, 'draft': False, 'pull_request': {'url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/14731', 'html_url': 'https://github.com/dolphin-emu/dolphin/pull/14731', 'diff_url': 'https://github.com/dolphin-emu/dolphin/pull/14731.diff', 'patch_url': 'https://github.com/dolphin-emu/dolphin/pull/14731.patch', 'merged_at': None}, 'body': "This PR introduces Conversion **to** WBFS support. WBFS is the format that is used by USB Loaders on a real Wii device.\r\n\r\n## Design decisions & hardcoded values\r\nThe writer uses fixed sector sizes that match what [libwbfs (the reference implementation by kwiirk)](https://github.com/kwiirk/wbfs/blob/master/libwbfs/libwbfs.c#L128-L134) computes for a standard single-layer Wii disc. These 2 hardcodes are stable and work correctly across all my testings.\r\n- HD sector shift: 9 (512 bytes)\r\n- WBFS sector shift: 21 (2 MiB)\r\nThese are not configurable via the UI. All existing WBFS tools use these values, and since the aim is to support USB Loaders then this has been tested and it is working on a real Wii.\r\n\r\nConverting from WBFS is not enabled. The existing `WbfsFileReader` reports `DataSizeType::UpperBound`, and `ShouldAllowConversion()` requires `Accurate`. I am able to support this but since it was hardcoded by the Dolphin team I thought a discussion is warranted.\r\n\r\n## Testing\r\n- Verified with DolphinTool header and DolphinTool verify\r\n- Verified with wit FILETYPE and wit DUMP (Wiimm's ISO Tools recognizes valid WBFS structure, partitions, encryption)\r\n- Tested ISO to WBFS and RVZ to WBFS conversions\r\n- Output file sizes match Wii Backup Manager when scrubbing is enabled (~0.1% difference), works when scrubbing is disabled.\r\n- Output WBFS files play correctly in Dolphin\r\n- Output WBFS files play correctly on a real Wii using USB Loader GX e25c4f3\r\n", 'reactions': {'url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/14731/reactions', 'total_count': 2, '+1': 2, '-1': 0, 'laugh': 0, 'hooray': 0, 'confused': 0, 'heart': 0, 'rocket': 0, 'eyes': 0}, 'timeline_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/14731/timeline', 'performed_via_github_app': None, 'state_reason': None}, 'comment': {'url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/comments/5013376425', 'html_url': 'https://github.com/dolphin-emu/dolphin/pull/14731#issuecomment-5013376425', 'issue_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/14731', 'id': 5013376425, 'node_id': 'IC_kwDOALCn2M8AAAABKtINqQ', 'user': {'login': 'thethiny', 'id': 6018214, 'node_id': 'MDQ6VXNlcjYwMTgyMTQ=', 'avatar_url': 'https://avatars.githubusercontent.com/u/6018214?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/thethiny', 'html_url': 'https://github.com/thethiny', 'followers_url': 'https://api.github.com/users/thethiny/followers', 'following_url': 'https://api.github.com/users/thethiny/following{/other_user}', 'gists_url': 'https://api.github.com/users/thethiny/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/thethiny/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/thethiny/subscriptions', 'organizations_url': 'https://api.github.com/users/thethiny/orgs', 'repos_url': 'https://api.github.com/users/thethiny/repos', 'events_url': 'https://api.github.com/users/thethiny/events{/privacy}', 'received_events_url': 'https://api.github.com/users/thethiny/received_events', 'type': 'User', 'user_view_type': 'public', 'site_admin': False}, 'created_at': '2026-07-18T23:41:38Z', 'updated_at': '2026-07-18T23:41:38Z', 'body': "> I'm not sure about NKitHeader. Certainly better, and probably good enough to merge. But it now feels a little bloated, violates DRY.\r\n> \r\n> Maybe the flags would be better handled with `Common::BitStruct`? And some kind of template approach might be better for the Optional fields.\r\n\r\nThe question here would be, do we lose clarity for DRY? Because we are able to compact the 5 structs into a template but then ReadField hides the bounds check and memcpy behind a generic function, making it less immediately obvious what's happening at each step. Let me know which approach to take, meanwhile I will be implementing your changes.", 'author_association': 'NONE', 'reactions': {'url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/comments/5013376425/reactions', 'total_count': 0, '+1': 0, '-1': 0, 'laugh': 0, 'hooray': 0, 'confused': 0, 'heart': 0, 'rocket': 0, 'eyes': 0}, 'performed_via_github_app': None, 'minimized': None}, 'repository': {'id': 11577304, 'node_id': 'MDEwOlJlcG9zaXRvcnkxMTU3NzMwNA==', 'name': 'dolphin', 'full_name': 'dolphin-emu/dolphin', 'private': False, 'owner': {'login': 'dolphin-emu', 'id': 5050316, 'node_id': 'MDEyOk9yZ2FuaXphdGlvbjUwNTAzMTY=', 'avatar_url': 'https://avatars.githubusercontent.com/u/5050316?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/dolphin-emu', 'html_url': 'https://github.com/dolphin-emu', 'followers_url': 'https://api.github.com/users/dolphin-emu/followers', 'following_url': 'https://api.github.com/users/dolphin-emu/following{/other_user}', 'gists_url': 'https://api.github.com/users/dolphin-emu/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/dolphin-emu/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/dolphin-emu/subscriptions', 'organizations_url': 'https://api.github.com/users/dolphin-emu/orgs', 'repos_url': 'https://api.github.com/users/dolphin-emu/repos', 'events_url': 'https://api.github.com/users/dolphin-emu/events{/privacy}', 'received_events_url': 'https://api.github.com/users/dolphin-emu/received_events', 'type': 'Organization', 'user_view_type': 'public', 'site_admin': False}, 'html_url': 'https://github.com/dolphin-emu/dolphin', 'description': 'Dolphin is a GameCube / Wii emulator, allowing you to play games for these two platforms on PC with improvements.', 'fork': False, 'url': 'https://api.github.com/repos/dolphin-emu/dolphin', 'forks_url': 'https://api.github.com/repos/dolphin-emu/dolphin/forks', 'keys_url': 'https://api.github.com/repos/dolphin-emu/dolphin/keys{/key_id}', 'collaborators_url': 'https://api.github.com/repos/dolphin-emu/dolphin/collaborators{/collaborator}', 'teams_url': 'https://api.github.com/repos/dolphin-emu/dolphin/teams', 'hooks_url': 'https://api.github.com/repos/dolphin-emu/dolphin/hooks', 'issue_events_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/events{/number}', 'events_url': 'https://api.github.com/repos/dolphin-emu/dolphin/events', 'assignees_url': 'https://api.github.com/repos/dolphin-emu/dolphin/assignees{/user}', 'branches_url': 'https://api.github.com/repos/dolphin-emu/dolphin/branches{/branch}', 'tags_url': 'https://api.github.com/repos/dolphin-emu/dolphin/tags', 'blobs_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/blobs{/sha}', 'git_tags_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/tags{/sha}', 'git_refs_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/refs{/sha}', 'trees_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/trees{/sha}', 'statuses_url': 'https://api.github.com/repos/dolphin-emu/dolphin/statuses/{sha}', 'languages_url': 'https://api.github.com/repos/dolphin-emu/dolphin/languages', 'stargazers_url': 'https://api.github.com/repos/dolphin-emu/dolphin/stargazers', 'contributors_url': 'https://api.github.com/repos/dolphin-emu/dolphin/contributors', 'subscribers_url': 'https://api.github.com/repos/dolphin-emu/dolphin/subscribers', 'subscription_url': 'https://api.github.com/repos/dolphin-emu/dolphin/subscription', 'commits_url': 'https://api.github.com/repos/dolphin-emu/dolphin/commits{/sha}', 'git_commits_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/commits{/sha}', 'comments_url': 'https://api.github.com/repos/dolphin-emu/dolphin/comments{/number}', 'issue_comment_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/comments{/number}', 'contents_url': 'https://api.github.com/repos/dolphin-emu/dolphin/contents/{+path}', 'compare_url': 'https://api.github.com/repos/dolphin-emu/dolphin/compare/{base}...{head}', 'merges_url': 'https://api.github.com/repos/dolphin-emu/dolphin/merges', 'archive_url': 'https://api.github.com/repos/dolphin-emu/dolphin/{archive_format}{/ref}', 'downloads_url': 'https://api.github.com/repos/dolphin-emu/dolphin/downloads', 'issues_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues{/number}', 'pulls_url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls{/number}', 'milestones_url': 'https://api.github.com/repos/dolphin-emu/dolphin/milestones{/number}', 'notifications_url': 'https://api.github.com/repos/dolphin-emu/dolphin/notifications{?since,all,participating}', 'labels_url': 'https://api.github.com/repos/dolphin-emu/dolphin/labels{/name}', 'releases_url': 'https://api.github.com/repos/dolphin-emu/dolphin/releases{/id}', 'deployments_url': 'https://api.github.com/repos/dolphin-emu/dolphin/deployments', 'created_at': '2013-07-22T09:07:57Z', 'updated_at': '2026-07-18T23:13:54Z', 'pushed_at': '2026-07-18T10:34:54Z', 'git_url': 'git://github.com/dolphin-emu/dolphin.git', 'ssh_url': 'git@github.com:dolphin-emu/dolphin.git', 'clone_url': 'https://github.com/dolphin-emu/dolphin.git', 'svn_url': 'https://github.com/dolphin-emu/dolphin', 'homepage': 'https://dolphin-emu.org', 'size': 558448, 'stargazers_count': 15273, 'watchers_count': 15273, 'language': 'C++', 'has_issues': False, 'has_projects': False, 'has_downloads': True, 'has_wiki': True, 'has_pages': False, 'has_discussions': False, 'forks_count': 3162, 'mirror_url': None, 'archived': False, 'disabled': False, 'open_issues_count': 446, 'license': {'key': 'other', 'name': 'Other', 'spdx_id': 'NOASSERTION', 'url': None, 'node_id': 'MDc6TGljZW5zZTA='}, 'allow_forking': True, 'is_template': False, 'web_commit_signoff_required': False, 'has_pull_requests': True, 'pull_request_creation_policy': 'all', 'topics': ['cpp', 'emulation', 'emulator', 'gamecube', 'wii'], 'visibility': 'public', 'forks': 3162, 'open_issues': 446, 'watchers': 15273, 'default_branch': 'master', 'custom_properties': {}}, 'organization': {'login': 'dolphin-emu', 'id': 5050316, 'node_id': 'MDEyOk9yZ2FuaXphdGlvbjUwNTAzMTY=', 'url': 'https://api.github.com/orgs/dolphin-emu', 'repos_url': 'https://api.github.com/orgs/dolphin-emu/repos', 'events_url': 'https://api.github.com/orgs/dolphin-emu/events', 'hooks_url': 'https://api.github.com/orgs/dolphin-emu/hooks', 'issues_url': 'https://api.github.com/orgs/dolphin-emu/issues', 'members_url': 'https://api.github.com/orgs/dolphin-emu/members{/member}', 'public_members_url': 'https://api.github.com/orgs/dolphin-emu/public_members{/member}', 'avatar_url': 'https://avatars.githubusercontent.com/u/5050316?v=4', 'description': ''}, 'sender': {'login': 'thethiny', 'id': 6018214, 'node_id': 'MDQ6VXNlcjYwMTgyMTQ=', 'avatar_url': 'https://avatars.githubusercontent.com/u/6018214?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/thethiny', 'html_url': 'https://github.com/thethiny', 'followers_url': 'https://api.github.com/users/thethiny/followers', 'following_url': 'https://api.github.com/users/thethiny/following{/other_user}', 'gists_url': 'https://api.github.com/users/thethiny/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/thethiny/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/thethiny/subscriptions', 'organizations_url': 'https://api.github.com/users/thethiny/orgs', 'repos_url': 'https://api.github.com/users/thethiny/repos', 'events_url': 'https://api.github.com/users/thethiny/events{/privacy}', 'received_events_url': 'https://api.github.com/users/thethiny/received_events', 'type': 'User', 'user_view_type': 'public', 'site_admin': False}, 'installation': {'id': 35437981, 'node_id': 'MDIzOkludGVncmF0aW9uSW5zdGFsbGF0aW9uMzU0Mzc5ODE='}}, 'type': 'raw_gh_hook'}
2026-07-18T23:41:29.024934	{'source': 'webserver', 'gh_type': 'pull_request_review_comment', 'raw': {'action': 'created', 'comment': {'url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/comments/3609425504', 'pull_request_review_id': 4729506940, 'id': 3609425504, 'node_id': 'PRRC_kwDOALCn2M7XI3Zg', 'diff_hunk': '@@ -186,7 +380,304 @@ std::unique_ptr<WbfsFileReader> WbfsFileReader::Create(File::DirectIOFile file,\n   if (!reader->IsGood())\n     reader.reset();\n \n+  if (reader && reader->m_has_nkit_header)\n+    reader->ReadPartitionInfo();\n+\n   return reader;\n }\n \n+// Converts any disc image to WBFS with an NKit v2 header for lossless round-trips.\n+// Strips disc-level junk and partition-level junk (encrypted sectors whose decrypted\n+// content is zero or LFG padding), records a junk bitmap for reconstruction.\n+// See: https://github.com/dolphin-emu/dolphin/pull/14731\n+bool ConvertToWBFS(BlobReader* infile, const std::string& infile_path,\n+                   const std::string& outfile_path, const CompressCB& callback)\n+{\n+  ASSERT(infile->GetDataSizeType() == DataSizeType::Accurate ||\n+         infile->GetDataSizeType() == DataSizeType::UpperBound);\n+\n+  File::DirectIOFile outfile(outfile_path, File::AccessMode::Write);\n+  if (!outfile.IsOpen())\n+  {\n+    PanicAlertFmtT(\n+        "Failed to open the output file \\"{0}\\".\\n"\n+        "Check that you have permissions to write the target folder and that the media can "\n+        "be written.",\n+        outfile_path);\n+    return false;\n+  }\n+\n+  const u64 disc_size = infile->GetDataSize();\n+\n+  // These match the values used by standard WBFS tools (wwt, WBFS Manager)\n+  static constexpr u8 hd_sector_shift = 9;\n+  static constexpr u8 wbfs_sector_shift = 21;\n+  static constexpr u64 hd_sector_size = 1ull << hd_sector_shift;\n+  static constexpr u64 wbfs_sector_size = 1ull << wbfs_sector_shift;\n+\n+  const u64 blocks_per_disc = (disc_size + wbfs_sector_size - 1) / wbfs_sector_size;\n+  const u64 disc_info_size =\n+      Common::AlignUp(WII_DISC_HEADER_SIZE + blocks_per_disc * sizeof(u16), hd_sector_size);\n+\n+  // Read disc header (first 256 bytes contain disc_id, disc_num, title, etc.)\n+  std::vector<u8> disc_header(WII_DISC_HEADER_SIZE, 0);\n+  if (!infile->Read(0, WII_DISC_HEADER_SIZE, disc_header.data()))\n+  {\n+    PanicAlertFmtT("Failed to read from the input file \\"{0}\\".", infile_path);\n+    return false;\n+  }\n+\n+  // Use Volume for partition info and decrypted reads\n+  struct PartitionInfo\n+  {\n+    u64 data_offset;\n+    u64 data_size;\n+    Partition partition;\n+  };\n+  std::vector<PartitionInfo> partitions;\n+\n+  std::unique_ptr<VolumeDisc> volume = CreateDisc(infile_path);\n+  if (volume)\n+  {\n+    for (const Partition& partition : volume->GetPartitions())\n+    {\n+      const std::optional<u64> data_offset =\n+          volume->ReadSwappedAndShifted(partition.offset + 0x2B8, PARTITION_NONE);\n+      const std::optional<u64> data_size =\n+          volume->ReadSwappedAndShifted(partition.offset + 0x2BC, PARTITION_NONE);\n+      if (!data_offset || !data_size)\n+        continue;\n+\n+      PartitionInfo info;\n+      info.data_offset = partition.offset + *data_offset;\n+      info.data_size = *data_size;\n+      info.partition = partition;\n+      partitions.push_back(info);\n+    }\n+  }\n+\n+  // NKit v2 gap type bitmap: 1 bit per block, MSB-first, always sized for dual-layer\n+  const u64 gap_type_blocks = (DL_DVD_SIZE + wbfs_sector_size - 1) / wbfs_sector_size;\n+  const u64 gap_type_bytes = (gap_type_blocks + 7) / 8;\n+  std::vector<u8> gap_type(gap_type_bytes, 0);\n+\n+  // Compute data_start up front so we can write sectors during the scan\n+  const u64 data_start = Common::AlignUp(hd_sector_size + disc_info_size, wbfs_sector_size);\n+  const u16 wlba_base = static_cast<u16>(data_start / wbfs_sector_size);\n+\n+  // Single pass: scan, classify, hash, and write used sectors in one loop\n+  std::vector<u8> sector_buf(wbfs_sector_size, 0);\n+  std::vector<u16> wlba_table(blocks_per_disc, 0);\n+  u16 used_count = 0;\n+\n+  // NKit v2 stores four hash digests for verification\n+  auto sha1_ctx = Common::SHA1::CreateContext();\n+  u32 crc = Common::StartCRC32();\n+  mbedtls_md5_context md5_ctx{};\n+  mbedtls_md5_init(&md5_ctx);\n+  mbedtls_md5_starts_ret(&md5_ctx);\n+  XXH64_state_t* xxh_state = XXH64_createState();\n+  XXH64_reset(xxh_state, 0);\n+\n+  for (u64 i = 0; i < blocks_per_disc; i++)\n+  {\n+    if (i % 100 == 0)\n+    {\n+      const bool was_cancelled =\n+          !callback(Common::GetStringT("Converting"),\n+                    static_cast<float>(i) / static_cast<float>(blocks_per_disc));\n+      if (was_cancelled)\n+      {\n+        XXH64_freeState(xxh_state);\n+        mbedtls_md5_free(&md5_ctx);\n+        outfile.Close();\n+        File::Delete(outfile_path);\n+        return false;\n+      }\n+    }\n+\n+    const u64 offset = i * wbfs_sector_size;\n+    const size_t sz = static_cast<size_t>(std::min(wbfs_sector_size, disc_size - offset));\n+\n+    if (!infile->Read(offset, sz, sector_buf.data()))', 'path': 'Source/Core/DiscIO/WbfsBlob.cpp', 'commit_id': '24b41d58df2315831b74f76b95417f2739d02f9d', 'original_commit_id': '24b41d58df2315831b74f76b95417f2739d02f9d', 'user': {'login': 'phire', 'id': 138484, 'node_id': 'MDQ6VXNlcjEzODQ4NA==', 'avatar_url': 'https://avatars.githubusercontent.com/u/138484?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/phire', 'html_url': 'https://github.com/phire', 'followers_url': 'https://api.github.com/users/phire/followers', 'following_url': 'https://api.github.com/users/phire/following{/other_user}', 'gists_url': 'https://api.github.com/users/phire/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/phire/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/phire/subscriptions', 'organizations_url': 'https://api.github.com/users/phire/orgs', 'repos_url': 'https://api.github.com/users/phire/repos', 'events_url': 'https://api.github.com/users/phire/events{/privacy}', 'received_events_url': 'https://api.github.com/users/phire/received_events', 'type': 'User', 'user_view_type': 'public', 'site_admin': False}, 'body': 'Oh... I forgot about the digests. Guess we do need it. ', 'created_at': '2026-07-18T23:41:27Z', 'updated_at': '2026-07-18T23:41:27Z', 'html_url': 'https://github.com/dolphin-emu/dolphin/pull/14731#discussion_r3609425504', 'pull_request_url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/14731', '_links': {'self': {'href': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/comments/3609425504'}, 'html': {'href': 'https://github.com/dolphin-emu/dolphin/pull/14731#discussion_r3609425504'}, 'pull_request': {'href': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/14731'}}, 'reactions': {'url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/comments/3609425504/reactions', 'total_count': 0, '+1': 0, '-1': 0, 'laugh': 0, 'hooray': 0, 'confused': 0, 'heart': 0, 'rocket': 0, 'eyes': 0}, 'start_line': None, 'original_start_line': None, 'start_side': None, 'line': 502, 'original_line': 502, 'side': 'RIGHT', 'in_reply_to_id': 3609251889, 'author_association': 'MEMBER', 'original_position': 409, 'position': 409, 'subject_type': 'line'}, 'pull_request': {'url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/14731', 'id': 4056977334, 'node_id': 'PR_kwDOALCn2M7x0I-2', 'html_url': 'https://github.com/dolphin-emu/dolphin/pull/14731', 'diff_url': 'https://github.com/dolphin-emu/dolphin/pull/14731.diff', 'patch_url': 'https://github.com/dolphin-emu/dolphin/pull/14731.patch', 'issue_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/14731', 'number': 14731, 'state': 'open', 'locked': False, 'title': 'Convert To WBFS Support', 'user': {'login': 'thethiny', 'id': 6018214, 'node_id': 'MDQ6VXNlcjYwMTgyMTQ=', 'avatar_url': 'https://avatars.githubusercontent.com/u/6018214?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/thethiny', 'html_url': 'https://github.com/thethiny', 'followers_url': 'https://api.github.com/users/thethiny/followers', 'following_url': 'https://api.github.com/users/thethiny/following{/other_user}', 'gists_url': 'https://api.github.com/users/thethiny/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/thethiny/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/thethiny/subscriptions', 'organizations_url': 'https://api.github.com/users/thethiny/orgs', 'repos_url': 'https://api.github.com/users/thethiny/repos', 'events_url': 'https://api.github.com/users/thethiny/events{/privacy}', 'received_events_url': 'https://api.github.com/users/thethiny/received_events', 'type': 'User', 'user_view_type': 'public', 'site_admin': False}, 'body': "This PR introduces Conversion **to** WBFS support. WBFS is the format that is used by USB Loaders on a real Wii device.\r\n\r\n## Design decisions & hardcoded values\r\nThe writer uses fixed sector sizes that match what [libwbfs (the reference implementation by kwiirk)](https://github.com/kwiirk/wbfs/blob/master/libwbfs/libwbfs.c#L128-L134) computes for a standard single-layer Wii disc. These 2 hardcodes are stable and work correctly across all my testings.\r\n- HD sector shift: 9 (512 bytes)\r\n- WBFS sector shift: 21 (2 MiB)\r\nThese are not configurable via the UI. All existing WBFS tools use these values, and since the aim is to support USB Loaders then this has been tested and it is working on a real Wii.\r\n\r\nConverting from WBFS is not enabled. The existing `WbfsFileReader` reports `DataSizeType::UpperBound`, and `ShouldAllowConversion()` requires `Accurate`. I am able to support this but since it was hardcoded by the Dolphin team I thought a discussion is warranted.\r\n\r\n## Testing\r\n- Verified with DolphinTool header and DolphinTool verify\r\n- Verified with wit FILETYPE and wit DUMP (Wiimm's ISO Tools recognizes valid WBFS structure, partitions, encryption)\r\n- Tested ISO to WBFS and RVZ to WBFS conversions\r\n- Output file sizes match Wii Backup Manager when scrubbing is enabled (~0.1% difference), works when scrubbing is disabled.\r\n- Output WBFS files play correctly in Dolphin\r\n- Output WBFS files play correctly on a real Wii using USB Loader GX e25c4f3\r\n", 'created_at': '2026-07-15T01:16:25Z', 'updated_at': '2026-07-18T23:37:35Z', 'closed_at': None, 'merged_at': None, 'merge_commit_sha': '228f93416dd80eb09da834ad7852c8eaa4d9212b', 'assignees': [], 'requested_reviewers': [], 'requested_teams': [], 'labels': [], 'milestone': None, 'draft': False, 'commits_url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/14731/commits', 'review_comments_url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/14731/comments', 'review_comment_url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/comments{/number}', 'comments_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/14731/comments', 'statuses_url': 'https://api.github.com/repos/dolphin-emu/dolphin/statuses/24b41d58df2315831b74f76b95417f2739d02f9d', 'head': {'label': 'thethiny:wbfs-conversion', 'ref': 'wbfs-conversion', 'sha': '24b41d58df2315831b74f76b95417f2739d02f9d', 'user': {'login': 'thethiny', 'id': 6018214, 'node_id': 'MDQ6VXNlcjYwMTgyMTQ=', 'avatar_url': 'https://avatars.githubusercontent.com/u/6018214?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/thethiny', 'html_url': 'https://github.com/thethiny', 'followers_url': 'https://api.github.com/users/thethiny/followers', 'following_url': 'https://api.github.com/users/thethiny/following{/other_user}', 'gists_url': 'https://api.github.com/users/thethiny/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/thethiny/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/thethiny/subscriptions', 'organizations_url': 'https://api.github.com/users/thethiny/orgs', 'repos_url': 'https://api.github.com/users/thethiny/repos', 'events_url': 'https://api.github.com/users/thethiny/events{/privacy}', 'received_events_url': 'https://api.github.com/users/thethiny/received_events', 'type': 'User', 'user_view_type': 'public', 'site_admin': False}, 'repo': {'id': 1298654395, 'node_id': 'R_kgDOTWfkuw', 'name': 'dolphin', 'full_name': 'thethiny/dolphin', 'private': False, 'owner': {'login': 'thethiny', 'id': 6018214, 'node_id': 'MDQ6VXNlcjYwMTgyMTQ=', 'avatar_url': 'https://avatars.githubusercontent.com/u/6018214?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/thethiny', 'html_url': 'https://github.com/thethiny', 'followers_url': 'https://api.github.com/users/thethiny/followers', 'following_url': 'https://api.github.com/users/thethiny/following{/other_user}', 'gists_url': 'https://api.github.com/users/thethiny/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/thethiny/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/thethiny/subscriptions', 'organizations_url': 'https://api.github.com/users/thethiny/orgs', 'repos_url': 'https://api.github.com/users/thethiny/repos', 'events_url': 'https://api.github.com/users/thethiny/events{/privacy}', 'received_events_url': 'https://api.github.com/users/thethiny/received_events', 'type': 'User', 'user_view_type': 'public', 'site_admin': False}, 'html_url': 'https://github.com/thethiny/dolphin', 'description': 'Dolphin is a GameCube / Wii emulator, allowing you to play games for these two platforms on PC with improvements.', 'fork': True, 'url': 'https://api.github.com/repos/thethiny/dolphin', 'forks_url': 'https://api.github.com/repos/thethiny/dolphin/forks', 'keys_url': 'https://api.github.com/repos/thethiny/dolphin/keys{/key_id}', 'collaborators_url': 'https://api.github.com/repos/thethiny/dolphin/collaborators{/collaborator}', 'teams_url': 'https://api.github.com/repos/thethiny/dolphin/teams', 'hooks_url': 'https://api.github.com/repos/thethiny/dolphin/hooks', 'issue_events_url': 'https://api.github.com/repos/thethiny/dolphin/issues/events{/number}', 'events_url': 'https://api.github.com/repos/thethiny/dolphin/events', 'assignees_url': 'https://api.github.com/repos/thethiny/dolphin/assignees{/user}', 'branches_url': 'https://api.github.com/repos/thethiny/dolphin/branches{/branch}', 'tags_url': 'https://api.github.com/repos/thethiny/dolphin/tags', 'blobs_url': 'https://api.github.com/repos/thethiny/dolphin/git/blobs{/sha}', 'git_tags_url': 'https://api.github.com/repos/thethiny/dolphin/git/tags{/sha}', 'git_refs_url': 'https://api.github.com/repos/thethiny/dolphin/git/refs{/sha}', 'trees_url': 'https://api.github.com/repos/thethiny/dolphin/git/trees{/sha}', 'statuses_url': 'https://api.github.com/repos/thethiny/dolphin/statuses/{sha}', 'languages_url': 'https://api.github.com/repos/thethiny/dolphin/languages', 'stargazers_url': 'https://api.github.com/repos/thethiny/dolphin/stargazers', 'contributors_url': 'https://api.github.com/repos/thethiny/dolphin/contributors', 'subscribers_url': 'https://api.github.com/repos/thethiny/dolphin/subscribers', 'subscription_url': 'https://api.github.com/repos/thethiny/dolphin/subscription', 'commits_url': 'https://api.github.com/repos/thethiny/dolphin/commits{/sha}', 'git_commits_url': 'https://api.github.com/repos/thethiny/dolphin/git/commits{/sha}', 'comments_url': 'https://api.github.com/repos/thethiny/dolphin/comments{/number}', 'issue_comment_url': 'https://api.github.com/repos/thethiny/dolphin/issues/comments{/number}', 'contents_url': 'https://api.github.com/repos/thethiny/dolphin/contents/{+path}', 'compare_url': 'https://api.github.com/repos/thethiny/dolphin/compare/{base}...{head}', 'merges_url': 'https://api.github.com/repos/thethiny/dolphin/merges', 'archive_url': 'https://api.github.com/repos/thethiny/dolphin/{archive_format}{/ref}', 'downloads_url': 'https://api.github.com/repos/thethiny/dolphin/downloads', 'issues_url': 'https://api.github.com/repos/thethiny/dolphin/issues{/number}', 'pulls_url': 'https://api.github.com/repos/thethiny/dolphin/pulls{/number}', 'milestones_url': 'https://api.github.com/repos/thethiny/dolphin/milestones{/number}', 'notifications_url': 'https://api.github.com/repos/thethiny/dolphin/notifications{?since,all,participating}', 'labels_url': 'https://api.github.com/repos/thethiny/dolphin/labels{/name}', 'releases_url': 'https://api.github.com/repos/thethiny/dolphin/releases{/id}', 'deployments_url': 'https://api.github.com/repos/thethiny/dolphin/deployments', 'created_at': '2026-07-12T22:09:13Z', 'updated_at': '2026-07-12T22:09:13Z', 'pushed_at': '2026-07-18T20:35:03Z', 'git_url': 'git://github.com/thethiny/dolphin.git', 'ssh_url': 'git@github.com:thethiny/dolphin.git', 'clone_url': 'https://github.com/thethiny/dolphin.git', 'svn_url': 'https://github.com/thethiny/dolphin', 'homepage': 'https://dolphin-emu.org', 'size': 515471, 'stargazers_count': 0, 'watchers_count': 0, 'language': None, 'has_issues': False, 'has_projects': True, 'has_downloads': True, 'has_wiki': True, 'has_pages': False, 'has_discussions': False, 'forks_count': 0, 'mirror_url': None, 'archived': False, 'disabled': False, 'open_issues_count': 0, 'license': {'key': 'other', 'name': 'Other', 'spdx_id': 'NOASSERTION', 'url': None, 'node_id': 'MDc6TGljZW5zZTA='}, 'allow_forking': True, 'is_template': False, 'web_commit_signoff_required': False, 'has_pull_requests': True, 'pull_request_creation_policy': 'all', 'topics': [], 'visibility': 'public', 'forks': 0, 'open_issues': 0, 'watchers': 0, 'default_branch': 'master', 'allow_squash_merge': True, 'allow_merge_commit': True, 'allow_rebase_merge': True, 'allow_auto_merge': False, 'delete_branch_on_merge': False, 'allow_update_branch': False, 'use_squash_pr_title_as_default': False, 'squash_merge_commit_message': 'COMMIT_MESSAGES', 'squash_merge_commit_title': 'COMMIT_OR_PR_TITLE', 'merge_commit_message': 'PR_TITLE', 'merge_commit_title': 'MERGE_MESSAGE'}}, 'base': {'label': 'dolphin-emu:master', 'ref': 'master', 'sha': 'd3b2943807dd0073f7767947466dd73cccfef319', 'user': {'login': 'dolphin-emu', 'id': 5050316, 'node_id': 'MDEyOk9yZ2FuaXphdGlvbjUwNTAzMTY=', 'avatar_url': 'https://avatars.githubusercontent.com/u/5050316?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/dolphin-emu', 'html_url': 'https://github.com/dolphin-emu', 'followers_url': 'https://api.github.com/users/dolphin-emu/followers', 'following_url': 'https://api.github.com/users/dolphin-emu/following{/other_user}', 'gists_url': 'https://api.github.com/users/dolphin-emu/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/dolphin-emu/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/dolphin-emu/subscriptions', 'organizations_url': 'https://api.github.com/users/dolphin-emu/orgs', 'repos_url': 'https://api.github.com/users/dolphin-emu/repos', 'events_url': 'https://api.github.com/users/dolphin-emu/events{/privacy}', 'received_events_url': 'https://api.github.com/users/dolphin-emu/received_events', 'type': 'Organization', 'user_view_type': 'public', 'site_admin': False}, 'repo': {'id': 11577304, 'node_id': 'MDEwOlJlcG9zaXRvcnkxMTU3NzMwNA==', 'name': 'dolphin', 'full_name': 'dolphin-emu/dolphin', 'private': False, 'owner': {'login': 'dolphin-emu', 'id': 5050316, 'node_id': 'MDEyOk9yZ2FuaXphdGlvbjUwNTAzMTY=', 'avatar_url': 'https://avatars.githubusercontent.com/u/5050316?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/dolphin-emu', 'html_url': 'https://github.com/dolphin-emu', 'followers_url': 'https://api.github.com/users/dolphin-emu/followers', 'following_url': 'https://api.github.com/users/dolphin-emu/following{/other_user}', 'gists_url': 'https://api.github.com/users/dolphin-emu/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/dolphin-emu/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/dolphin-emu/subscriptions', 'organizations_url': 'https://api.github.com/users/dolphin-emu/orgs', 'repos_url': 'https://api.github.com/users/dolphin-emu/repos', 'events_url': 'https://api.github.com/users/dolphin-emu/events{/privacy}', 'received_events_url': 'https://api.github.com/users/dolphin-emu/received_events', 'type': 'Organization', 'user_view_type': 'public', 'site_admin': False}, 'html_url': 'https://github.com/dolphin-emu/dolphin', 'description': 'Dolphin is a GameCube / Wii emulator, allowing you to play games for these two platforms on PC with improvements.', 'fork': False, 'url': 'https://api.github.com/repos/dolphin-emu/dolphin', 'forks_url': 'https://api.github.com/repos/dolphin-emu/dolphin/forks', 'keys_url': 'https://api.github.com/repos/dolphin-emu/dolphin/keys{/key_id}', 'collaborators_url': 'https://api.github.com/repos/dolphin-emu/dolphin/collaborators{/collaborator}', 'teams_url': 'https://api.github.com/repos/dolphin-emu/dolphin/teams', 'hooks_url': 'https://api.github.com/repos/dolphin-emu/dolphin/hooks', 'issue_events_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/events{/number}', 'events_url': 'https://api.github.com/repos/dolphin-emu/dolphin/events', 'assignees_url': 'https://api.github.com/repos/dolphin-emu/dolphin/assignees{/user}', 'branches_url': 'https://api.github.com/repos/dolphin-emu/dolphin/branches{/branch}', 'tags_url': 'https://api.github.com/repos/dolphin-emu/dolphin/tags', 'blobs_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/blobs{/sha}', 'git_tags_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/tags{/sha}', 'git_refs_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/refs{/sha}', 'trees_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/trees{/sha}', 'statuses_url': 'https://api.github.com/repos/dolphin-emu/dolphin/statuses/{sha}', 'languages_url': 'https://api.github.com/repos/dolphin-emu/dolphin/languages', 'stargazers_url': 'https://api.github.com/repos/dolphin-emu/dolphin/stargazers', 'contributors_url': 'https://api.github.com/repos/dolphin-emu/dolphin/contributors', 'subscribers_url': 'https://api.github.com/repos/dolphin-emu/dolphin/subscribers', 'subscription_url': 'https://api.github.com/repos/dolphin-emu/dolphin/subscription', 'commits_url': 'https://api.github.com/repos/dolphin-emu/dolphin/commits{/sha}', 'git_commits_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/commits{/sha}', 'comments_url': 'https://api.github.com/repos/dolphin-emu/dolphin/comments{/number}', 'issue_comment_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/comments{/number}', 'contents_url': 'https://api.github.com/repos/dolphin-emu/dolphin/contents/{+path}', 'compare_url': 'https://api.github.com/repos/dolphin-emu/dolphin/compare/{base}...{head}', 'merges_url': 'https://api.github.com/repos/dolphin-emu/dolphin/merges', 'archive_url': 'https://api.github.com/repos/dolphin-emu/dolphin/{archive_format}{/ref}', 'downloads_url': 'https://api.github.com/repos/dolphin-emu/dolphin/downloads', 'issues_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues{/number}', 'pulls_url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls{/number}', 'milestones_url': 'https://api.github.com/repos/dolphin-emu/dolphin/milestones{/number}', 'notifications_url': 'https://api.github.com/repos/dolphin-emu/dolphin/notifications{?since,all,participating}', 'labels_url': 'https://api.github.com/repos/dolphin-emu/dolphin/labels{/name}', 'releases_url': 'https://api.github.com/repos/dolphin-emu/dolphin/releases{/id}', 'deployments_url': 'https://api.github.com/repos/dolphin-emu/dolphin/deployments', 'created_at': '2013-07-22T09:07:57Z', 'updated_at': '2026-07-18T23:13:54Z', 'pushed_at': '2026-07-18T10:34:54Z', 'git_url': 'git://github.com/dolphin-emu/dolphin.git', 'ssh_url': 'git@github.com:dolphin-emu/dolphin.git', 'clone_url': 'https://github.com/dolphin-emu/dolphin.git', 'svn_url': 'https://github.com/dolphin-emu/dolphin', 'homepage': 'https://dolphin-emu.org', 'size': 558448, 'stargazers_count': 15273, 'watchers_count': 15273, 'language': 'C++', 'has_issues': False, 'has_projects': False, 'has_downloads': True, 'has_wiki': True, 'has_pages': False, 'has_discussions': False, 'forks_count': 3162, 'mirror_url': None, 'archived': False, 'disabled': False, 'open_issues_count': 446, 'license': {'key': 'other', 'name': 'Other', 'spdx_id': 'NOASSERTION', 'url': None, 'node_id': 'MDc6TGljZW5zZTA='}, 'allow_forking': True, 'is_template': False, 'web_commit_signoff_required': False, 'has_pull_requests': True, 'pull_request_creation_policy': 'all', 'topics': ['cpp', 'emulation', 'emulator', 'gamecube', 'wii'], 'visibility': 'public', 'forks': 3162, 'open_issues': 446, 'watchers': 15273, 'default_branch': 'master', 'allow_squash_merge': False, 'allow_merge_commit': True, 'allow_rebase_merge': False, 'allow_auto_merge': False, 'delete_branch_on_merge': False, 'allow_update_branch': False, 'use_squash_pr_title_as_default': False, 'squash_merge_commit_message': 'COMMIT_MESSAGES', 'squash_merge_commit_title': 'COMMIT_OR_PR_TITLE', 'merge_commit_message': 'PR_TITLE', 'merge_commit_title': 'MERGE_MESSAGE'}}, '_links': {'self': {'href': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/14731'}, 'html': {'href': 'https://github.com/dolphin-emu/dolphin/pull/14731'}, 'issue': {'href': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/14731'}, 'comments': {'href': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/14731/comments'}, 'review_comments': {'href': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/14731/comments'}, 'review_comment': {'href': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/comments{/number}'}, 'commits': {'href': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/14731/commits'}, 'statuses': {'href': 'https://api.github.com/repos/dolphin-emu/dolphin/statuses/24b41d58df2315831b74f76b95417f2739d02f9d'}}, 'author_association': 'NONE', 'auto_merge': None, 'assignee': None, 'active_lock_reason': None}, 'repository': {'id': 11577304, 'node_id': 'MDEwOlJlcG9zaXRvcnkxMTU3NzMwNA==', 'name': 'dolphin', 'full_name': 'dolphin-emu/dolphin', 'private': False, 'owner': {'login': 'dolphin-emu', 'id': 5050316, 'node_id': 'MDEyOk9yZ2FuaXphdGlvbjUwNTAzMTY=', 'avatar_url': 'https://avatars.githubusercontent.com/u/5050316?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/dolphin-emu', 'html_url': 'https://github.com/dolphin-emu', 'followers_url': 'https://api.github.com/users/dolphin-emu/followers', 'following_url': 'https://api.github.com/users/dolphin-emu/following{/other_user}', 'gists_url': 'https://api.github.com/users/dolphin-emu/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/dolphin-emu/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/dolphin-emu/subscriptions', 'organizations_url': 'https://api.github.com/users/dolphin-emu/orgs', 'repos_url': 'https://api.github.com/users/dolphin-emu/repos', 'events_url': 'https://api.github.com/users/dolphin-emu/events{/privacy}', 'received_events_url': 'https://api.github.com/users/dolphin-emu/received_events', 'type': 'Organization', 'user_view_type': 'public', 'site_admin': False}, 'html_url': 'https://github.com/dolphin-emu/dolphin', 'description': 'Dolphin is a GameCube / Wii emulator, allowing you to play games for these two platforms on PC with improvements.', 'fork': False, 'url': 'https://api.github.com/repos/dolphin-emu/dolphin', 'forks_url': 'https://api.github.com/repos/dolphin-emu/dolphin/forks', 'keys_url': 'https://api.github.com/repos/dolphin-emu/dolphin/keys{/key_id}', 'collaborators_url': 'https://api.github.com/repos/dolphin-emu/dolphin/collaborators{/collaborator}', 'teams_url': 'https://api.github.com/repos/dolphin-emu/dolphin/teams', 'hooks_url': 'https://api.github.com/repos/dolphin-emu/dolphin/hooks', 'issue_events_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/events{/number}', 'events_url': 'https://api.github.com/repos/dolphin-emu/dolphin/events', 'assignees_url': 'https://api.github.com/repos/dolphin-emu/dolphin/assignees{/user}', 'branches_url': 'https://api.github.com/repos/dolphin-emu/dolphin/branches{/branch}', 'tags_url': 'https://api.github.com/repos/dolphin-emu/dolphin/tags', 'blobs_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/blobs{/sha}', 'git_tags_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/tags{/sha}', 'git_refs_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/refs{/sha}', 'trees_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/trees{/sha}', 'statuses_url': 'https://api.github.com/repos/dolphin-emu/dolphin/statuses/{sha}', 'languages_url': 'https://api.github.com/repos/dolphin-emu/dolphin/languages', 'stargazers_url': 'https://api.github.com/repos/dolphin-emu/dolphin/stargazers', 'contributors_url': 'https://api.github.com/repos/dolphin-emu/dolphin/contributors', 'subscribers_url': 'https://api.github.com/repos/dolphin-emu/dolphin/subscribers', 'subscription_url': 'https://api.github.com/repos/dolphin-emu/dolphin/subscription', 'commits_url': 'https://api.github.com/repos/dolphin-emu/dolphin/commits{/sha}', 'git_commits_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/commits{/sha}', 'comments_url': 'https://api.github.com/repos/dolphin-emu/dolphin/comments{/number}', 'issue_comment_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/comments{/number}', 'contents_url': 'https://api.github.com/repos/dolphin-emu/dolphin/contents/{+path}', 'compare_url': 'https://api.github.com/repos/dolphin-emu/dolphin/compare/{base}...{head}', 'merges_url': 'https://api.github.com/repos/dolphin-emu/dolphin/merges', 'archive_url': 'https://api.github.com/repos/dolphin-emu/dolphin/{archive_format}{/ref}', 'downloads_url': 'https://api.github.com/repos/dolphin-emu/dolphin/downloads', 'issues_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues{/number}', 'pulls_url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls{/number}', 'milestones_url': 'https://api.github.com/repos/dolphin-emu/dolphin/milestones{/number}', 'notifications_url': 'https://api.github.com/repos/dolphin-emu/dolphin/notifications{?since,all,participating}', 'labels_url': 'https://api.github.com/repos/dolphin-emu/dolphin/labels{/name}', 'releases_url': 'https://api.github.com/repos/dolphin-emu/dolphin/releases{/id}', 'deployments_url': 'https://api.github.com/repos/dolphin-emu/dolphin/deployments', 'created_at': '2013-07-22T09:07:57Z', 'updated_at': '2026-07-18T23:13:54Z', 'pushed_at': '2026-07-18T10:34:54Z', 'git_url': 'git://github.com/dolphin-emu/dolphin.git', 'ssh_url': 'git@github.com:dolphin-emu/dolphin.git', 'clone_url': 'https://github.com/dolphin-emu/dolphin.git', 'svn_url': 'https://github.com/dolphin-emu/dolphin', 'homepage': 'https://dolphin-emu.org', 'size': 558448, 'stargazers_count': 15273, 'watchers_count': 15273, 'language': 'C++', 'has_issues': False, 'has_projects': False, 'has_downloads': True, 'has_wiki': True, 'has_pages': False, 'has_discussions': False, 'forks_count': 3162, 'mirror_url': None, 'archived': False, 'disabled': False, 'open_issues_count': 446, 'license': {'key': 'other', 'name': 'Other', 'spdx_id': 'NOASSERTION', 'url': None, 'node_id': 'MDc6TGljZW5zZTA='}, 'allow_forking': True, 'is_template': False, 'web_commit_signoff_required': False, 'has_pull_requests': True, 'pull_request_creation_policy': 'all', 'topics': ['cpp', 'emulation', 'emulator', 'gamecube', 'wii'], 'visibility': 'public', 'forks': 3162, 'open_issues': 446, 'watchers': 15273, 'default_branch': 'master', 'custom_properties': {}}, 'organization': {'login': 'dolphin-emu', 'id': 5050316, 'node_id': 'MDEyOk9yZ2FuaXphdGlvbjUwNTAzMTY=', 'url': 'https://api.github.com/orgs/dolphin-emu', 'repos_url': 'https://api.github.com/orgs/dolphin-emu/repos', 'events_url': 'https://api.github.com/orgs/dolphin-emu/events', 'hooks_url': 'https://api.github.com/orgs/dolphin-emu/hooks', 'issues_url': 'https://api.github.com/orgs/dolphin-emu/issues', 'members_url': 'https://api.github.com/orgs/dolphin-emu/members{/member}', 'public_members_url': 'https://api.github.com/orgs/dolphin-emu/public_members{/member}', 'avatar_url': 'https://avatars.githubusercontent.com/u/5050316?v=4', 'description': ''}, 'sender': {'login': 'phire', 'id': 138484, 'node_id': 'MDQ6VXNlcjEzODQ4NA==', 'avatar_url': 'https://avatars.githubusercontent.com/u/138484?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/phire', 'html_url': 'https://github.com/phire', 'followers_url': 'https://api.github.com/users/phire/followers', 'following_url': 'https://api.github.com/users/phire/following{/other_user}', 'gists_url': 'https://api.github.com/users/phire/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/phire/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/phire/subscriptions', 'organizations_url': 'https://api.github.com/users/phire/orgs', 'repos_url': 'https://api.github.com/users/phire/repos', 'events_url': 'https://api.github.com/users/phire/events{/privacy}', 'received_events_url': 'https://api.github.com/users/phire/received_events', 'type': 'User', 'user_view_type': 'public', 'site_admin': False}, 'installation': {'id': 35437981, 'node_id': 'MDIzOkludGVncmF0aW9uSW5zdGFsbGF0aW9uMzU0Mzc5ODE='}}, 'type': 'raw_gh_hook'}
2026-07-18T23:41:29.022761	{'source': 'webserver', 'gh_type': 'pull_request_review', 'raw': {'action': 'submitted', 'review': {'id': 4729506940, 'node_id': 'PRR_kwDOALCn2M8AAAABGeaMfA', 'user': {'login': 'phire', 'id': 138484, 'node_id': 'MDQ6VXNlcjEzODQ4NA==', 'avatar_url': 'https://avatars.githubusercontent.com/u/138484?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/phire', 'html_url': 'https://github.com/phire', 'followers_url': 'https://api.github.com/users/phire/followers', 'following_url': 'https://api.github.com/users/phire/following{/other_user}', 'gists_url': 'https://api.github.com/users/phire/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/phire/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/phire/subscriptions', 'organizations_url': 'https://api.github.com/users/phire/orgs', 'repos_url': 'https://api.github.com/users/phire/repos', 'events_url': 'https://api.github.com/users/phire/events{/privacy}', 'received_events_url': 'https://api.github.com/users/phire/received_events', 'type': 'User', 'user_view_type': 'public', 'site_admin': False}, 'body': None, 'commit_id': '24b41d58df2315831b74f76b95417f2739d02f9d', 'state': 'commented', 'html_url': 'https://github.com/dolphin-emu/dolphin/pull/14731#pullrequestreview-4729506940', 'pull_request_url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/14731', '_links': {'html': {'href': 'https://github.com/dolphin-emu/dolphin/pull/14731#pullrequestreview-4729506940'}, 'pull_request': {'href': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/14731'}}, 'submitted_at': '2026-07-18T23:41:27Z', 'updated_at': '2026-07-18T23:41:27Z', 'author_association': 'MEMBER'}, 'pull_request': {'url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/14731', 'id': 4056977334, 'node_id': 'PR_kwDOALCn2M7x0I-2', 'html_url': 'https://github.com/dolphin-emu/dolphin/pull/14731', 'diff_url': 'https://github.com/dolphin-emu/dolphin/pull/14731.diff', 'patch_url': 'https://github.com/dolphin-emu/dolphin/pull/14731.patch', 'issue_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/14731', 'number': 14731, 'state': 'open', 'locked': False, 'title': 'Convert To WBFS Support', 'user': {'login': 'thethiny', 'id': 6018214, 'node_id': 'MDQ6VXNlcjYwMTgyMTQ=', 'avatar_url': 'https://avatars.githubusercontent.com/u/6018214?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/thethiny', 'html_url': 'https://github.com/thethiny', 'followers_url': 'https://api.github.com/users/thethiny/followers', 'following_url': 'https://api.github.com/users/thethiny/following{/other_user}', 'gists_url': 'https://api.github.com/users/thethiny/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/thethiny/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/thethiny/subscriptions', 'organizations_url': 'https://api.github.com/users/thethiny/orgs', 'repos_url': 'https://api.github.com/users/thethiny/repos', 'events_url': 'https://api.github.com/users/thethiny/events{/privacy}', 'received_events_url': 'https://api.github.com/users/thethiny/received_events', 'type': 'User', 'user_view_type': 'public', 'site_admin': False}, 'body': "This PR introduces Conversion **to** WBFS support. WBFS is the format that is used by USB Loaders on a real Wii device.\r\n\r\n## Design decisions & hardcoded values\r\nThe writer uses fixed sector sizes that match what [libwbfs (the reference implementation by kwiirk)](https://github.com/kwiirk/wbfs/blob/master/libwbfs/libwbfs.c#L128-L134) computes for a standard single-layer Wii disc. These 2 hardcodes are stable and work correctly across all my testings.\r\n- HD sector shift: 9 (512 bytes)\r\n- WBFS sector shift: 21 (2 MiB)\r\nThese are not configurable via the UI. All existing WBFS tools use these values, and since the aim is to support USB Loaders then this has been tested and it is working on a real Wii.\r\n\r\nConverting from WBFS is not enabled. The existing `WbfsFileReader` reports `DataSizeType::UpperBound`, and `ShouldAllowConversion()` requires `Accurate`. I am able to support this but since it was hardcoded by the Dolphin team I thought a discussion is warranted.\r\n\r\n## Testing\r\n- Verified with DolphinTool header and DolphinTool verify\r\n- Verified with wit FILETYPE and wit DUMP (Wiimm's ISO Tools recognizes valid WBFS structure, partitions, encryption)\r\n- Tested ISO to WBFS and RVZ to WBFS conversions\r\n- Output file sizes match Wii Backup Manager when scrubbing is enabled (~0.1% difference), works when scrubbing is disabled.\r\n- Output WBFS files play correctly in Dolphin\r\n- Output WBFS files play correctly on a real Wii using USB Loader GX e25c4f3\r\n", 'created_at': '2026-07-15T01:16:25Z', 'updated_at': '2026-07-18T23:37:35Z', 'closed_at': None, 'merged_at': None, 'merge_commit_sha': '228f93416dd80eb09da834ad7852c8eaa4d9212b', 'assignees': [], 'requested_reviewers': [], 'requested_teams': [], 'labels': [], 'milestone': None, 'draft': False, 'commits_url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/14731/commits', 'review_comments_url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/14731/comments', 'review_comment_url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/comments{/number}', 'comments_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/14731/comments', 'statuses_url': 'https://api.github.com/repos/dolphin-emu/dolphin/statuses/24b41d58df2315831b74f76b95417f2739d02f9d', 'head': {'label': 'thethiny:wbfs-conversion', 'ref': 'wbfs-conversion', 'sha': '24b41d58df2315831b74f76b95417f2739d02f9d', 'user': {'login': 'thethiny', 'id': 6018214, 'node_id': 'MDQ6VXNlcjYwMTgyMTQ=', 'avatar_url': 'https://avatars.githubusercontent.com/u/6018214?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/thethiny', 'html_url': 'https://github.com/thethiny', 'followers_url': 'https://api.github.com/users/thethiny/followers', 'following_url': 'https://api.github.com/users/thethiny/following{/other_user}', 'gists_url': 'https://api.github.com/users/thethiny/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/thethiny/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/thethiny/subscriptions', 'organizations_url': 'https://api.github.com/users/thethiny/orgs', 'repos_url': 'https://api.github.com/users/thethiny/repos', 'events_url': 'https://api.github.com/users/thethiny/events{/privacy}', 'received_events_url': 'https://api.github.com/users/thethiny/received_events', 'type': 'User', 'user_view_type': 'public', 'site_admin': False}, 'repo': {'id': 1298654395, 'node_id': 'R_kgDOTWfkuw', 'name': 'dolphin', 'full_name': 'thethiny/dolphin', 'private': False, 'owner': {'login': 'thethiny', 'id': 6018214, 'node_id': 'MDQ6VXNlcjYwMTgyMTQ=', 'avatar_url': 'https://avatars.githubusercontent.com/u/6018214?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/thethiny', 'html_url': 'https://github.com/thethiny', 'followers_url': 'https://api.github.com/users/thethiny/followers', 'following_url': 'https://api.github.com/users/thethiny/following{/other_user}', 'gists_url': 'https://api.github.com/users/thethiny/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/thethiny/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/thethiny/subscriptions', 'organizations_url': 'https://api.github.com/users/thethiny/orgs', 'repos_url': 'https://api.github.com/users/thethiny/repos', 'events_url': 'https://api.github.com/users/thethiny/events{/privacy}', 'received_events_url': 'https://api.github.com/users/thethiny/received_events', 'type': 'User', 'user_view_type': 'public', 'site_admin': False}, 'html_url': 'https://github.com/thethiny/dolphin', 'description': 'Dolphin is a GameCube / Wii emulator, allowing you to play games for these two platforms on PC with improvements.', 'fork': True, 'url': 'https://api.github.com/repos/thethiny/dolphin', 'forks_url': 'https://api.github.com/repos/thethiny/dolphin/forks', 'keys_url': 'https://api.github.com/repos/thethiny/dolphin/keys{/key_id}', 'collaborators_url': 'https://api.github.com/repos/thethiny/dolphin/collaborators{/collaborator}', 'teams_url': 'https://api.github.com/repos/thethiny/dolphin/teams', 'hooks_url': 'https://api.github.com/repos/thethiny/dolphin/hooks', 'issue_events_url': 'https://api.github.com/repos/thethiny/dolphin/issues/events{/number}', 'events_url': 'https://api.github.com/repos/thethiny/dolphin/events', 'assignees_url': 'https://api.github.com/repos/thethiny/dolphin/assignees{/user}', 'branches_url': 'https://api.github.com/repos/thethiny/dolphin/branches{/branch}', 'tags_url': 'https://api.github.com/repos/thethiny/dolphin/tags', 'blobs_url': 'https://api.github.com/repos/thethiny/dolphin/git/blobs{/sha}', 'git_tags_url': 'https://api.github.com/repos/thethiny/dolphin/git/tags{/sha}', 'git_refs_url': 'https://api.github.com/repos/thethiny/dolphin/git/refs{/sha}', 'trees_url': 'https://api.github.com/repos/thethiny/dolphin/git/trees{/sha}', 'statuses_url': 'https://api.github.com/repos/thethiny/dolphin/statuses/{sha}', 'languages_url': 'https://api.github.com/repos/thethiny/dolphin/languages', 'stargazers_url': 'https://api.github.com/repos/thethiny/dolphin/stargazers', 'contributors_url': 'https://api.github.com/repos/thethiny/dolphin/contributors', 'subscribers_url': 'https://api.github.com/repos/thethiny/dolphin/subscribers', 'subscription_url': 'https://api.github.com/repos/thethiny/dolphin/subscription', 'commits_url': 'https://api.github.com/repos/thethiny/dolphin/commits{/sha}', 'git_commits_url': 'https://api.github.com/repos/thethiny/dolphin/git/commits{/sha}', 'comments_url': 'https://api.github.com/repos/thethiny/dolphin/comments{/number}', 'issue_comment_url': 'https://api.github.com/repos/thethiny/dolphin/issues/comments{/number}', 'contents_url': 'https://api.github.com/repos/thethiny/dolphin/contents/{+path}', 'compare_url': 'https://api.github.com/repos/thethiny/dolphin/compare/{base}...{head}', 'merges_url': 'https://api.github.com/repos/thethiny/dolphin/merges', 'archive_url': 'https://api.github.com/repos/thethiny/dolphin/{archive_format}{/ref}', 'downloads_url': 'https://api.github.com/repos/thethiny/dolphin/downloads', 'issues_url': 'https://api.github.com/repos/thethiny/dolphin/issues{/number}', 'pulls_url': 'https://api.github.com/repos/thethiny/dolphin/pulls{/number}', 'milestones_url': 'https://api.github.com/repos/thethiny/dolphin/milestones{/number}', 'notifications_url': 'https://api.github.com/repos/thethiny/dolphin/notifications{?since,all,participating}', 'labels_url': 'https://api.github.com/repos/thethiny/dolphin/labels{/name}', 'releases_url': 'https://api.github.com/repos/thethiny/dolphin/releases{/id}', 'deployments_url': 'https://api.github.com/repos/thethiny/dolphin/deployments', 'created_at': '2026-07-12T22:09:13Z', 'updated_at': '2026-07-12T22:09:13Z', 'pushed_at': '2026-07-18T20:35:03Z', 'git_url': 'git://github.com/thethiny/dolphin.git', 'ssh_url': 'git@github.com:thethiny/dolphin.git', 'clone_url': 'https://github.com/thethiny/dolphin.git', 'svn_url': 'https://github.com/thethiny/dolphin', 'homepage': 'https://dolphin-emu.org', 'size': 515471, 'stargazers_count': 0, 'watchers_count': 0, 'language': None, 'has_issues': False, 'has_projects': True, 'has_downloads': True, 'has_wiki': True, 'has_pages': False, 'has_discussions': False, 'forks_count': 0, 'mirror_url': None, 'archived': False, 'disabled': False, 'open_issues_count': 0, 'license': {'key': 'other', 'name': 'Other', 'spdx_id': 'NOASSERTION', 'url': None, 'node_id': 'MDc6TGljZW5zZTA='}, 'allow_forking': True, 'is_template': False, 'web_commit_signoff_required': False, 'has_pull_requests': True, 'pull_request_creation_policy': 'all', 'topics': [], 'visibility': 'public', 'forks': 0, 'open_issues': 0, 'watchers': 0, 'default_branch': 'master', 'allow_squash_merge': True, 'allow_merge_commit': True, 'allow_rebase_merge': True, 'allow_auto_merge': False, 'delete_branch_on_merge': False, 'allow_update_branch': False, 'use_squash_pr_title_as_default': False, 'squash_merge_commit_message': 'COMMIT_MESSAGES', 'squash_merge_commit_title': 'COMMIT_OR_PR_TITLE', 'merge_commit_message': 'PR_TITLE', 'merge_commit_title': 'MERGE_MESSAGE'}}, 'base': {'label': 'dolphin-emu:master', 'ref': 'master', 'sha': 'd3b2943807dd0073f7767947466dd73cccfef319', 'user': {'login': 'dolphin-emu', 'id': 5050316, 'node_id': 'MDEyOk9yZ2FuaXphdGlvbjUwNTAzMTY=', 'avatar_url': 'https://avatars.githubusercontent.com/u/5050316?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/dolphin-emu', 'html_url': 'https://github.com/dolphin-emu', 'followers_url': 'https://api.github.com/users/dolphin-emu/followers', 'following_url': 'https://api.github.com/users/dolphin-emu/following{/other_user}', 'gists_url': 'https://api.github.com/users/dolphin-emu/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/dolphin-emu/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/dolphin-emu/subscriptions', 'organizations_url': 'https://api.github.com/users/dolphin-emu/orgs', 'repos_url': 'https://api.github.com/users/dolphin-emu/repos', 'events_url': 'https://api.github.com/users/dolphin-emu/events{/privacy}', 'received_events_url': 'https://api.github.com/users/dolphin-emu/received_events', 'type': 'Organization', 'user_view_type': 'public', 'site_admin': False}, 'repo': {'id': 11577304, 'node_id': 'MDEwOlJlcG9zaXRvcnkxMTU3NzMwNA==', 'name': 'dolphin', 'full_name': 'dolphin-emu/dolphin', 'private': False, 'owner': {'login': 'dolphin-emu', 'id': 5050316, 'node_id': 'MDEyOk9yZ2FuaXphdGlvbjUwNTAzMTY=', 'avatar_url': 'https://avatars.githubusercontent.com/u/5050316?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/dolphin-emu', 'html_url': 'https://github.com/dolphin-emu', 'followers_url': 'https://api.github.com/users/dolphin-emu/followers', 'following_url': 'https://api.github.com/users/dolphin-emu/following{/other_user}', 'gists_url': 'https://api.github.com/users/dolphin-emu/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/dolphin-emu/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/dolphin-emu/subscriptions', 'organizations_url': 'https://api.github.com/users/dolphin-emu/orgs', 'repos_url': 'https://api.github.com/users/dolphin-emu/repos', 'events_url': 'https://api.github.com/users/dolphin-emu/events{/privacy}', 'received_events_url': 'https://api.github.com/users/dolphin-emu/received_events', 'type': 'Organization', 'user_view_type': 'public', 'site_admin': False}, 'html_url': 'https://github.com/dolphin-emu/dolphin', 'description': 'Dolphin is a GameCube / Wii emulator, allowing you to play games for these two platforms on PC with improvements.', 'fork': False, 'url': 'https://api.github.com/repos/dolphin-emu/dolphin', 'forks_url': 'https://api.github.com/repos/dolphin-emu/dolphin/forks', 'keys_url': 'https://api.github.com/repos/dolphin-emu/dolphin/keys{/key_id}', 'collaborators_url': 'https://api.github.com/repos/dolphin-emu/dolphin/collaborators{/collaborator}', 'teams_url': 'https://api.github.com/repos/dolphin-emu/dolphin/teams', 'hooks_url': 'https://api.github.com/repos/dolphin-emu/dolphin/hooks', 'issue_events_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/events{/number}', 'events_url': 'https://api.github.com/repos/dolphin-emu/dolphin/events', 'assignees_url': 'https://api.github.com/repos/dolphin-emu/dolphin/assignees{/user}', 'branches_url': 'https://api.github.com/repos/dolphin-emu/dolphin/branches{/branch}', 'tags_url': 'https://api.github.com/repos/dolphin-emu/dolphin/tags', 'blobs_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/blobs{/sha}', 'git_tags_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/tags{/sha}', 'git_refs_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/refs{/sha}', 'trees_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/trees{/sha}', 'statuses_url': 'https://api.github.com/repos/dolphin-emu/dolphin/statuses/{sha}', 'languages_url': 'https://api.github.com/repos/dolphin-emu/dolphin/languages', 'stargazers_url': 'https://api.github.com/repos/dolphin-emu/dolphin/stargazers', 'contributors_url': 'https://api.github.com/repos/dolphin-emu/dolphin/contributors', 'subscribers_url': 'https://api.github.com/repos/dolphin-emu/dolphin/subscribers', 'subscription_url': 'https://api.github.com/repos/dolphin-emu/dolphin/subscription', 'commits_url': 'https://api.github.com/repos/dolphin-emu/dolphin/commits{/sha}', 'git_commits_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/commits{/sha}', 'comments_url': 'https://api.github.com/repos/dolphin-emu/dolphin/comments{/number}', 'issue_comment_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/comments{/number}', 'contents_url': 'https://api.github.com/repos/dolphin-emu/dolphin/contents/{+path}', 'compare_url': 'https://api.github.com/repos/dolphin-emu/dolphin/compare/{base}...{head}', 'merges_url': 'https://api.github.com/repos/dolphin-emu/dolphin/merges', 'archive_url': 'https://api.github.com/repos/dolphin-emu/dolphin/{archive_format}{/ref}', 'downloads_url': 'https://api.github.com/repos/dolphin-emu/dolphin/downloads', 'issues_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues{/number}', 'pulls_url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls{/number}', 'milestones_url': 'https://api.github.com/repos/dolphin-emu/dolphin/milestones{/number}', 'notifications_url': 'https://api.github.com/repos/dolphin-emu/dolphin/notifications{?since,all,participating}', 'labels_url': 'https://api.github.com/repos/dolphin-emu/dolphin/labels{/name}', 'releases_url': 'https://api.github.com/repos/dolphin-emu/dolphin/releases{/id}', 'deployments_url': 'https://api.github.com/repos/dolphin-emu/dolphin/deployments', 'created_at': '2013-07-22T09:07:57Z', 'updated_at': '2026-07-18T23:13:54Z', 'pushed_at': '2026-07-18T10:34:54Z', 'git_url': 'git://github.com/dolphin-emu/dolphin.git', 'ssh_url': 'git@github.com:dolphin-emu/dolphin.git', 'clone_url': 'https://github.com/dolphin-emu/dolphin.git', 'svn_url': 'https://github.com/dolphin-emu/dolphin', 'homepage': 'https://dolphin-emu.org', 'size': 558448, 'stargazers_count': 15273, 'watchers_count': 15273, 'language': 'C++', 'has_issues': False, 'has_projects': False, 'has_downloads': True, 'has_wiki': True, 'has_pages': False, 'has_discussions': False, 'forks_count': 3162, 'mirror_url': None, 'archived': False, 'disabled': False, 'open_issues_count': 446, 'license': {'key': 'other', 'name': 'Other', 'spdx_id': 'NOASSERTION', 'url': None, 'node_id': 'MDc6TGljZW5zZTA='}, 'allow_forking': True, 'is_template': False, 'web_commit_signoff_required': False, 'has_pull_requests': True, 'pull_request_creation_policy': 'all', 'topics': ['cpp', 'emulation', 'emulator', 'gamecube', 'wii'], 'visibility': 'public', 'forks': 3162, 'open_issues': 446, 'watchers': 15273, 'default_branch': 'master', 'allow_squash_merge': False, 'allow_merge_commit': True, 'allow_rebase_merge': False, 'allow_auto_merge': False, 'delete_branch_on_merge': False, 'allow_update_branch': False, 'use_squash_pr_title_as_default': False, 'squash_merge_commit_message': 'COMMIT_MESSAGES', 'squash_merge_commit_title': 'COMMIT_OR_PR_TITLE', 'merge_commit_message': 'PR_TITLE', 'merge_commit_title': 'MERGE_MESSAGE'}}, '_links': {'self': {'href': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/14731'}, 'html': {'href': 'https://github.com/dolphin-emu/dolphin/pull/14731'}, 'issue': {'href': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/14731'}, 'comments': {'href': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/14731/comments'}, 'review_comments': {'href': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/14731/comments'}, 'review_comment': {'href': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/comments{/number}'}, 'commits': {'href': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/14731/commits'}, 'statuses': {'href': 'https://api.github.com/repos/dolphin-emu/dolphin/statuses/24b41d58df2315831b74f76b95417f2739d02f9d'}}, 'author_association': 'NONE', 'auto_merge': None, 'assignee': None, 'active_lock_reason': None}, 'repository': {'id': 11577304, 'node_id': 'MDEwOlJlcG9zaXRvcnkxMTU3NzMwNA==', 'name': 'dolphin', 'full_name': 'dolphin-emu/dolphin', 'private': False, 'owner': {'login': 'dolphin-emu', 'id': 5050316, 'node_id': 'MDEyOk9yZ2FuaXphdGlvbjUwNTAzMTY=', 'avatar_url': 'https://avatars.githubusercontent.com/u/5050316?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/dolphin-emu', 'html_url': 'https://github.com/dolphin-emu', 'followers_url': 'https://api.github.com/users/dolphin-emu/followers', 'following_url': 'https://api.github.com/users/dolphin-emu/following{/other_user}', 'gists_url': 'https://api.github.com/users/dolphin-emu/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/dolphin-emu/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/dolphin-emu/subscriptions', 'organizations_url': 'https://api.github.com/users/dolphin-emu/orgs', 'repos_url': 'https://api.github.com/users/dolphin-emu/repos', 'events_url': 'https://api.github.com/users/dolphin-emu/events{/privacy}', 'received_events_url': 'https://api.github.com/users/dolphin-emu/received_events', 'type': 'Organization', 'user_view_type': 'public', 'site_admin': False}, 'html_url': 'https://github.com/dolphin-emu/dolphin', 'description': 'Dolphin is a GameCube / Wii emulator, allowing you to play games for these two platforms on PC with improvements.', 'fork': False, 'url': 'https://api.github.com/repos/dolphin-emu/dolphin', 'forks_url': 'https://api.github.com/repos/dolphin-emu/dolphin/forks', 'keys_url': 'https://api.github.com/repos/dolphin-emu/dolphin/keys{/key_id}', 'collaborators_url': 'https://api.github.com/repos/dolphin-emu/dolphin/collaborators{/collaborator}', 'teams_url': 'https://api.github.com/repos/dolphin-emu/dolphin/teams', 'hooks_url': 'https://api.github.com/repos/dolphin-emu/dolphin/hooks', 'issue_events_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/events{/number}', 'events_url': 'https://api.github.com/repos/dolphin-emu/dolphin/events', 'assignees_url': 'https://api.github.com/repos/dolphin-emu/dolphin/assignees{/user}', 'branches_url': 'https://api.github.com/repos/dolphin-emu/dolphin/branches{/branch}', 'tags_url': 'https://api.github.com/repos/dolphin-emu/dolphin/tags', 'blobs_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/blobs{/sha}', 'git_tags_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/tags{/sha}', 'git_refs_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/refs{/sha}', 'trees_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/trees{/sha}', 'statuses_url': 'https://api.github.com/repos/dolphin-emu/dolphin/statuses/{sha}', 'languages_url': 'https://api.github.com/repos/dolphin-emu/dolphin/languages', 'stargazers_url': 'https://api.github.com/repos/dolphin-emu/dolphin/stargazers', 'contributors_url': 'https://api.github.com/repos/dolphin-emu/dolphin/contributors', 'subscribers_url': 'https://api.github.com/repos/dolphin-emu/dolphin/subscribers', 'subscription_url': 'https://api.github.com/repos/dolphin-emu/dolphin/subscription', 'commits_url': 'https://api.github.com/repos/dolphin-emu/dolphin/commits{/sha}', 'git_commits_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/commits{/sha}', 'comments_url': 'https://api.github.com/repos/dolphin-emu/dolphin/comments{/number}', 'issue_comment_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/comments{/number}', 'contents_url': 'https://api.github.com/repos/dolphin-emu/dolphin/contents/{+path}', 'compare_url': 'https://api.github.com/repos/dolphin-emu/dolphin/compare/{base}...{head}', 'merges_url': 'https://api.github.com/repos/dolphin-emu/dolphin/merges', 'archive_url': 'https://api.github.com/repos/dolphin-emu/dolphin/{archive_format}{/ref}', 'downloads_url': 'https://api.github.com/repos/dolphin-emu/dolphin/downloads', 'issues_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues{/number}', 'pulls_url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls{/number}', 'milestones_url': 'https://api.github.com/repos/dolphin-emu/dolphin/milestones{/number}', 'notifications_url': 'https://api.github.com/repos/dolphin-emu/dolphin/notifications{?since,all,participating}', 'labels_url': 'https://api.github.com/repos/dolphin-emu/dolphin/labels{/name}', 'releases_url': 'https://api.github.com/repos/dolphin-emu/dolphin/releases{/id}', 'deployments_url': 'https://api.github.com/repos/dolphin-emu/dolphin/deployments', 'created_at': '2013-07-22T09:07:57Z', 'updated_at': '2026-07-18T23:13:54Z', 'pushed_at': '2026-07-18T10:34:54Z', 'git_url': 'git://github.com/dolphin-emu/dolphin.git', 'ssh_url': 'git@github.com:dolphin-emu/dolphin.git', 'clone_url': 'https://github.com/dolphin-emu/dolphin.git', 'svn_url': 'https://github.com/dolphin-emu/dolphin', 'homepage': 'https://dolphin-emu.org', 'size': 558448, 'stargazers_count': 15273, 'watchers_count': 15273, 'language': 'C++', 'has_issues': False, 'has_projects': False, 'has_downloads': True, 'has_wiki': True, 'has_pages': False, 'has_discussions': False, 'forks_count': 3162, 'mirror_url': None, 'archived': False, 'disabled': False, 'open_issues_count': 446, 'license': {'key': 'other', 'name': 'Other', 'spdx_id': 'NOASSERTION', 'url': None, 'node_id': 'MDc6TGljZW5zZTA='}, 'allow_forking': True, 'is_template': False, 'web_commit_signoff_required': False, 'has_pull_requests': True, 'pull_request_creation_policy': 'all', 'topics': ['cpp', 'emulation', 'emulator', 'gamecube', 'wii'], 'visibility': 'public', 'forks': 3162, 'open_issues': 446, 'watchers': 15273, 'default_branch': 'master', 'custom_properties': {}}, 'organization': {'login': 'dolphin-emu', 'id': 5050316, 'node_id': 'MDEyOk9yZ2FuaXphdGlvbjUwNTAzMTY=', 'url': 'https://api.github.com/orgs/dolphin-emu', 'repos_url': 'https://api.github.com/orgs/dolphin-emu/repos', 'events_url': 'https://api.github.com/orgs/dolphin-emu/events', 'hooks_url': 'https://api.github.com/orgs/dolphin-emu/hooks', 'issues_url': 'https://api.github.com/orgs/dolphin-emu/issues', 'members_url': 'https://api.github.com/orgs/dolphin-emu/members{/member}', 'public_members_url': 'https://api.github.com/orgs/dolphin-emu/public_members{/member}', 'avatar_url': 'https://avatars.githubusercontent.com/u/5050316?v=4', 'description': ''}, 'sender': {'login': 'phire', 'id': 138484, 'node_id': 'MDQ6VXNlcjEzODQ4NA==', 'avatar_url': 'https://avatars.githubusercontent.com/u/138484?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/phire', 'html_url': 'https://github.com/phire', 'followers_url': 'https://api.github.com/users/phire/followers', 'following_url': 'https://api.github.com/users/phire/following{/other_user}', 'gists_url': 'https://api.github.com/users/phire/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/phire/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/phire/subscriptions', 'organizations_url': 'https://api.github.com/users/phire/orgs', 'repos_url': 'https://api.github.com/users/phire/repos', 'events_url': 'https://api.github.com/users/phire/events{/privacy}', 'received_events_url': 'https://api.github.com/users/phire/received_events', 'type': 'User', 'user_view_type': 'public', 'site_admin': False}, 'installation': {'id': 35437981, 'node_id': 'MDIzOkludGVncmF0aW9uSW5zdGFsbGF0aW9uMzU0Mzc5ODE='}}, 'type': 'raw_gh_hook'}
2026-07-18T23:37:37.476246	{'source': 'webserver', 'gh_type': 'pull_request_review_comment', 'raw': {'action': 'created', 'comment': {'url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/comments/3609419546', 'pull_request_review_id': 4729501733, 'id': 3609419546, 'node_id': 'PRRC_kwDOALCn2M7XI18a', 'diff_hunk': '@@ -186,7 +380,304 @@ std::unique_ptr<WbfsFileReader> WbfsFileReader::Create(File::DirectIOFile file,\n   if (!reader->IsGood())\n     reader.reset();\n \n+  if (reader && reader->m_has_nkit_header)\n+    reader->ReadPartitionInfo();\n+\n   return reader;\n }\n \n+// Converts any disc image to WBFS with an NKit v2 header for lossless round-trips.\n+// Strips disc-level junk and partition-level junk (encrypted sectors whose decrypted\n+// content is zero or LFG padding), records a junk bitmap for reconstruction.\n+// See: https://github.com/dolphin-emu/dolphin/pull/14731\n+bool ConvertToWBFS(BlobReader* infile, const std::string& infile_path,\n+                   const std::string& outfile_path, const CompressCB& callback)\n+{\n+  ASSERT(infile->GetDataSizeType() == DataSizeType::Accurate ||\n+         infile->GetDataSizeType() == DataSizeType::UpperBound);\n+\n+  File::DirectIOFile outfile(outfile_path, File::AccessMode::Write);\n+  if (!outfile.IsOpen())\n+  {\n+    PanicAlertFmtT(\n+        "Failed to open the output file \\"{0}\\".\\n"\n+        "Check that you have permissions to write the target folder and that the media can "\n+        "be written.",\n+        outfile_path);\n+    return false;\n+  }\n+\n+  const u64 disc_size = infile->GetDataSize();\n+\n+  // These match the values used by standard WBFS tools (wwt, WBFS Manager)\n+  static constexpr u8 hd_sector_shift = 9;\n+  static constexpr u8 wbfs_sector_shift = 21;\n+  static constexpr u64 hd_sector_size = 1ull << hd_sector_shift;\n+  static constexpr u64 wbfs_sector_size = 1ull << wbfs_sector_shift;\n+\n+  const u64 blocks_per_disc = (disc_size + wbfs_sector_size - 1) / wbfs_sector_size;\n+  const u64 disc_info_size =\n+      Common::AlignUp(WII_DISC_HEADER_SIZE + blocks_per_disc * sizeof(u16), hd_sector_size);\n+\n+  // Read disc header (first 256 bytes contain disc_id, disc_num, title, etc.)\n+  std::vector<u8> disc_header(WII_DISC_HEADER_SIZE, 0);\n+  if (!infile->Read(0, WII_DISC_HEADER_SIZE, disc_header.data()))\n+  {\n+    PanicAlertFmtT("Failed to read from the input file \\"{0}\\".", infile_path);\n+    return false;\n+  }\n+\n+  // Use Volume for partition info and decrypted reads\n+  struct PartitionInfo\n+  {\n+    u64 data_offset;\n+    u64 data_size;\n+    Partition partition;\n+  };\n+  std::vector<PartitionInfo> partitions;\n+\n+  std::unique_ptr<VolumeDisc> volume = CreateDisc(infile_path);\n+  if (volume)\n+  {\n+    for (const Partition& partition : volume->GetPartitions())\n+    {\n+      const std::optional<u64> data_offset =\n+          volume->ReadSwappedAndShifted(partition.offset + 0x2B8, PARTITION_NONE);\n+      const std::optional<u64> data_size =\n+          volume->ReadSwappedAndShifted(partition.offset + 0x2BC, PARTITION_NONE);\n+      if (!data_offset || !data_size)\n+        continue;\n+\n+      PartitionInfo info;\n+      info.data_offset = partition.offset + *data_offset;\n+      info.data_size = *data_size;\n+      info.partition = partition;\n+      partitions.push_back(info);\n+    }\n+  }\n+\n+  // NKit v2 gap type bitmap: 1 bit per block, MSB-first, always sized for dual-layer\n+  const u64 gap_type_blocks = (DL_DVD_SIZE + wbfs_sector_size - 1) / wbfs_sector_size;\n+  const u64 gap_type_bytes = (gap_type_blocks + 7) / 8;\n+  std::vector<u8> gap_type(gap_type_bytes, 0);\n+\n+  // Compute data_start up front so we can write sectors during the scan\n+  const u64 data_start = Common::AlignUp(hd_sector_size + disc_info_size, wbfs_sector_size);\n+  const u16 wlba_base = static_cast<u16>(data_start / wbfs_sector_size);\n+\n+  // Single pass: scan, classify, hash, and write used sectors in one loop\n+  std::vector<u8> sector_buf(wbfs_sector_size, 0);\n+  std::vector<u16> wlba_table(blocks_per_disc, 0);\n+  u16 used_count = 0;\n+\n+  // NKit v2 stores four hash digests for verification\n+  auto sha1_ctx = Common::SHA1::CreateContext();\n+  u32 crc = Common::StartCRC32();\n+  mbedtls_md5_context md5_ctx{};\n+  mbedtls_md5_init(&md5_ctx);\n+  mbedtls_md5_starts_ret(&md5_ctx);\n+  XXH64_state_t* xxh_state = XXH64_createState();\n+  XXH64_reset(xxh_state, 0);\n+\n+  for (u64 i = 0; i < blocks_per_disc; i++)\n+  {\n+    if (i % 100 == 0)\n+    {\n+      const bool was_cancelled =\n+          !callback(Common::GetStringT("Converting"),\n+                    static_cast<float>(i) / static_cast<float>(blocks_per_disc));\n+      if (was_cancelled)\n+      {\n+        XXH64_freeState(xxh_state);\n+        mbedtls_md5_free(&md5_ctx);\n+        outfile.Close();\n+        File::Delete(outfile_path);\n+        return false;\n+      }\n+    }\n+\n+    const u64 offset = i * wbfs_sector_size;\n+    const size_t sz = static_cast<size_t>(std::min(wbfs_sector_size, disc_size - offset));\n+\n+    if (!infile->Read(offset, sz, sector_buf.data()))\n+    {\n+      PanicAlertFmtT("Failed to read from the input file \\"{0}\\".", infile_path);\n+      XXH64_freeState(xxh_state);\n+      mbedtls_md5_free(&md5_ctx);\n+      outfile.Close();\n+      File::Delete(outfile_path);\n+      return false;\n+    }\n+\n+    // Update all four hashes with the full disc data\n+    sha1_ctx->Update(sector_buf.data(), sz);\n+    crc = Common::UpdateCRC32(crc, sector_buf.data(), sz);\n+    mbedtls_md5_update_ret(&md5_ctx, sector_buf.data(), sz);\n+    XXH64_update(xxh_state, sector_buf.data(), sz);\n+\n+    // Find which partition (if any) this block belongs to\n+    const u32 start_sector = static_cast<u32>(offset / VolumeWii::BLOCK_TOTAL_SIZE);\n+    const u32 end_sector = static_cast<u32>((offset + sz) / VolumeWii::BLOCK_TOTAL_SIZE);\n+    const auto it = std::ranges::find_if(partitions, [&](const PartitionInfo& p) {\n+      const u32 p_start = static_cast<u32>(p.data_offset / VolumeWii::BLOCK_TOTAL_SIZE);\n+      const u32 p_end =\n+          static_cast<u32>((p.data_offset + p.data_size) / VolumeWii::BLOCK_TOTAL_SIZE);', 'path': 'Source/Core/DiscIO/WbfsBlob.cpp', 'commit_id': '24b41d58df2315831b74f76b95417f2739d02f9d', 'original_commit_id': '24b41d58df2315831b74f76b95417f2739d02f9d', 'user': {'login': 'thethiny', 'id': 6018214, 'node_id': 'MDQ6VXNlcjYwMTgyMTQ=', 'avatar_url': 'https://avatars.githubusercontent.com/u/6018214?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/thethiny', 'html_url': 'https://github.com/thethiny', 'followers_url': 'https://api.github.com/users/thethiny/followers', 'following_url': 'https://api.github.com/users/thethiny/following{/other_user}', 'gists_url': 'https://api.github.com/users/thethiny/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/thethiny/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/thethiny/subscriptions', 'organizations_url': 'https://api.github.com/users/thethiny/orgs', 'repos_url': 'https://api.github.com/users/thethiny/repos', 'events_url': 'https://api.github.com/users/thethiny/events{/privacy}', 'received_events_url': 'https://api.github.com/users/thethiny/received_events', 'type': 'User', 'user_view_type': 'public', 'site_admin': False}, 'body': 'this is an oversight on my end due to iterative coding. Noted', 'created_at': '2026-07-18T23:37:35Z', 'updated_at': '2026-07-18T23:37:35Z', 'html_url': 'https://github.com/dolphin-emu/dolphin/pull/14731#discussion_r3609419546', 'pull_request_url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/14731', '_links': {'self': {'href': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/comments/3609419546'}, 'html': {'href': 'https://github.com/dolphin-emu/dolphin/pull/14731#discussion_r3609419546'}, 'pull_request': {'href': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/14731'}}, 'reactions': {'url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/comments/3609419546/reactions', 'total_count': 0, '+1': 0, '-1': 0, 'laugh': 0, 'hooray': 0, 'confused': 0, 'heart': 0, 'rocket': 0, 'eyes': 0}, 'start_line': 519, 'original_start_line': 519, 'start_side': 'RIGHT', 'line': 524, 'original_line': 524, 'side': 'RIGHT', 'in_reply_to_id': 3609363364, 'author_association': 'NONE', 'original_position': 431, 'position': 431, 'subject_type': 'line'}, 'pull_request': {'url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/14731', 'id': 4056977334, 'node_id': 'PR_kwDOALCn2M7x0I-2', 'html_url': 'https://github.com/dolphin-emu/dolphin/pull/14731', 'diff_url': 'https://github.com/dolphin-emu/dolphin/pull/14731.diff', 'patch_url': 'https://github.com/dolphin-emu/dolphin/pull/14731.patch', 'issue_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/14731', 'number': 14731, 'state': 'open', 'locked': False, 'title': 'Convert To WBFS Support', 'user': {'login': 'thethiny', 'id': 6018214, 'node_id': 'MDQ6VXNlcjYwMTgyMTQ=', 'avatar_url': 'https://avatars.githubusercontent.com/u/6018214?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/thethiny', 'html_url': 'https://github.com/thethiny', 'followers_url': 'https://api.github.com/users/thethiny/followers', 'following_url': 'https://api.github.com/users/thethiny/following{/other_user}', 'gists_url': 'https://api.github.com/users/thethiny/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/thethiny/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/thethiny/subscriptions', 'organizations_url': 'https://api.github.com/users/thethiny/orgs', 'repos_url': 'https://api.github.com/users/thethiny/repos', 'events_url': 'https://api.github.com/users/thethiny/events{/privacy}', 'received_events_url': 'https://api.github.com/users/thethiny/received_events', 'type': 'User', 'user_view_type': 'public', 'site_admin': False}, 'body': "This PR introduces Conversion **to** WBFS support. WBFS is the format that is used by USB Loaders on a real Wii device.\r\n\r\n## Design decisions & hardcoded values\r\nThe writer uses fixed sector sizes that match what [libwbfs (the reference implementation by kwiirk)](https://github.com/kwiirk/wbfs/blob/master/libwbfs/libwbfs.c#L128-L134) computes for a standard single-layer Wii disc. These 2 hardcodes are stable and work correctly across all my testings.\r\n- HD sector shift: 9 (512 bytes)\r\n- WBFS sector shift: 21 (2 MiB)\r\nThese are not configurable via the UI. All existing WBFS tools use these values, and since the aim is to support USB Loaders then this has been tested and it is working on a real Wii.\r\n\r\nConverting from WBFS is not enabled. The existing `WbfsFileReader` reports `DataSizeType::UpperBound`, and `ShouldAllowConversion()` requires `Accurate`. I am able to support this but since it was hardcoded by the Dolphin team I thought a discussion is warranted.\r\n\r\n## Testing\r\n- Verified with DolphinTool header and DolphinTool verify\r\n- Verified with wit FILETYPE and wit DUMP (Wiimm's ISO Tools recognizes valid WBFS structure, partitions, encryption)\r\n- Tested ISO to WBFS and RVZ to WBFS conversions\r\n- Output file sizes match Wii Backup Manager when scrubbing is enabled (~0.1% difference), works when scrubbing is disabled.\r\n- Output WBFS files play correctly in Dolphin\r\n- Output WBFS files play correctly on a real Wii using USB Loader GX e25c4f3\r\n", 'created_at': '2026-07-15T01:16:25Z', 'updated_at': '2026-07-18T23:36:11Z', 'closed_at': None, 'merged_at': None, 'merge_commit_sha': '228f93416dd80eb09da834ad7852c8eaa4d9212b', 'assignees': [], 'requested_reviewers': [], 'requested_teams': [], 'labels': [], 'milestone': None, 'draft': False, 'commits_url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/14731/commits', 'review_comments_url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/14731/comments', 'review_comment_url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/comments{/number}', 'comments_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/14731/comments', 'statuses_url': 'https://api.github.com/repos/dolphin-emu/dolphin/statuses/24b41d58df2315831b74f76b95417f2739d02f9d', 'head': {'label': 'thethiny:wbfs-conversion', 'ref': 'wbfs-conversion', 'sha': '24b41d58df2315831b74f76b95417f2739d02f9d', 'user': {'login': 'thethiny', 'id': 6018214, 'node_id': 'MDQ6VXNlcjYwMTgyMTQ=', 'avatar_url': 'https://avatars.githubusercontent.com/u/6018214?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/thethiny', 'html_url': 'https://github.com/thethiny', 'followers_url': 'https://api.github.com/users/thethiny/followers', 'following_url': 'https://api.github.com/users/thethiny/following{/other_user}', 'gists_url': 'https://api.github.com/users/thethiny/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/thethiny/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/thethiny/subscriptions', 'organizations_url': 'https://api.github.com/users/thethiny/orgs', 'repos_url': 'https://api.github.com/users/thethiny/repos', 'events_url': 'https://api.github.com/users/thethiny/events{/privacy}', 'received_events_url': 'https://api.github.com/users/thethiny/received_events', 'type': 'User', 'user_view_type': 'public', 'site_admin': False}, 'repo': {'id': 1298654395, 'node_id': 'R_kgDOTWfkuw', 'name': 'dolphin', 'full_name': 'thethiny/dolphin', 'private': False, 'owner': {'login': 'thethiny', 'id': 6018214, 'node_id': 'MDQ6VXNlcjYwMTgyMTQ=', 'avatar_url': 'https://avatars.githubusercontent.com/u/6018214?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/thethiny', 'html_url': 'https://github.com/thethiny', 'followers_url': 'https://api.github.com/users/thethiny/followers', 'following_url': 'https://api.github.com/users/thethiny/following{/other_user}', 'gists_url': 'https://api.github.com/users/thethiny/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/thethiny/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/thethiny/subscriptions', 'organizations_url': 'https://api.github.com/users/thethiny/orgs', 'repos_url': 'https://api.github.com/users/thethiny/repos', 'events_url': 'https://api.github.com/users/thethiny/events{/privacy}', 'received_events_url': 'https://api.github.com/users/thethiny/received_events', 'type': 'User', 'user_view_type': 'public', 'site_admin': False}, 'html_url': 'https://github.com/thethiny/dolphin', 'description': 'Dolphin is a GameCube / Wii emulator, allowing you to play games for these two platforms on PC with improvements.', 'fork': True, 'url': 'https://api.github.com/repos/thethiny/dolphin', 'forks_url': 'https://api.github.com/repos/thethiny/dolphin/forks', 'keys_url': 'https://api.github.com/repos/thethiny/dolphin/keys{/key_id}', 'collaborators_url': 'https://api.github.com/repos/thethiny/dolphin/collaborators{/collaborator}', 'teams_url': 'https://api.github.com/repos/thethiny/dolphin/teams', 'hooks_url': 'https://api.github.com/repos/thethiny/dolphin/hooks', 'issue_events_url': 'https://api.github.com/repos/thethiny/dolphin/issues/events{/number}', 'events_url': 'https://api.github.com/repos/thethiny/dolphin/events', 'assignees_url': 'https://api.github.com/repos/thethiny/dolphin/assignees{/user}', 'branches_url': 'https://api.github.com/repos/thethiny/dolphin/branches{/branch}', 'tags_url': 'https://api.github.com/repos/thethiny/dolphin/tags', 'blobs_url': 'https://api.github.com/repos/thethiny/dolphin/git/blobs{/sha}', 'git_tags_url': 'https://api.github.com/repos/thethiny/dolphin/git/tags{/sha}', 'git_refs_url': 'https://api.github.com/repos/thethiny/dolphin/git/refs{/sha}', 'trees_url': 'https://api.github.com/repos/thethiny/dolphin/git/trees{/sha}', 'statuses_url': 'https://api.github.com/repos/thethiny/dolphin/statuses/{sha}', 'languages_url': 'https://api.github.com/repos/thethiny/dolphin/languages', 'stargazers_url': 'https://api.github.com/repos/thethiny/dolphin/stargazers', 'contributors_url': 'https://api.github.com/repos/thethiny/dolphin/contributors', 'subscribers_url': 'https://api.github.com/repos/thethiny/dolphin/subscribers', 'subscription_url': 'https://api.github.com/repos/thethiny/dolphin/subscription', 'commits_url': 'https://api.github.com/repos/thethiny/dolphin/commits{/sha}', 'git_commits_url': 'https://api.github.com/repos/thethiny/dolphin/git/commits{/sha}', 'comments_url': 'https://api.github.com/repos/thethiny/dolphin/comments{/number}', 'issue_comment_url': 'https://api.github.com/repos/thethiny/dolphin/issues/comments{/number}', 'contents_url': 'https://api.github.com/repos/thethiny/dolphin/contents/{+path}', 'compare_url': 'https://api.github.com/repos/thethiny/dolphin/compare/{base}...{head}', 'merges_url': 'https://api.github.com/repos/thethiny/dolphin/merges', 'archive_url': 'https://api.github.com/repos/thethiny/dolphin/{archive_format}{/ref}', 'downloads_url': 'https://api.github.com/repos/thethiny/dolphin/downloads', 'issues_url': 'https://api.github.com/repos/thethiny/dolphin/issues{/number}', 'pulls_url': 'https://api.github.com/repos/thethiny/dolphin/pulls{/number}', 'milestones_url': 'https://api.github.com/repos/thethiny/dolphin/milestones{/number}', 'notifications_url': 'https://api.github.com/repos/thethiny/dolphin/notifications{?since,all,participating}', 'labels_url': 'https://api.github.com/repos/thethiny/dolphin/labels{/name}', 'releases_url': 'https://api.github.com/repos/thethiny/dolphin/releases{/id}', 'deployments_url': 'https://api.github.com/repos/thethiny/dolphin/deployments', 'created_at': '2026-07-12T22:09:13Z', 'updated_at': '2026-07-12T22:09:13Z', 'pushed_at': '2026-07-18T20:35:03Z', 'git_url': 'git://github.com/thethiny/dolphin.git', 'ssh_url': 'git@github.com:thethiny/dolphin.git', 'clone_url': 'https://github.com/thethiny/dolphin.git', 'svn_url': 'https://github.com/thethiny/dolphin', 'homepage': 'https://dolphin-emu.org', 'size': 515471, 'stargazers_count': 0, 'watchers_count': 0, 'language': None, 'has_issues': False, 'has_projects': True, 'has_downloads': True, 'has_wiki': True, 'has_pages': False, 'has_discussions': False, 'forks_count': 0, 'mirror_url': None, 'archived': False, 'disabled': False, 'open_issues_count': 0, 'license': {'key': 'other', 'name': 'Other', 'spdx_id': 'NOASSERTION', 'url': None, 'node_id': 'MDc6TGljZW5zZTA='}, 'allow_forking': True, 'is_template': False, 'web_commit_signoff_required': False, 'has_pull_requests': True, 'pull_request_creation_policy': 'all', 'topics': [], 'visibility': 'public', 'forks': 0, 'open_issues': 0, 'watchers': 0, 'default_branch': 'master', 'allow_squash_merge': True, 'allow_merge_commit': True, 'allow_rebase_merge': True, 'allow_auto_merge': False, 'delete_branch_on_merge': False, 'allow_update_branch': False, 'use_squash_pr_title_as_default': False, 'squash_merge_commit_message': 'COMMIT_MESSAGES', 'squash_merge_commit_title': 'COMMIT_OR_PR_TITLE', 'merge_commit_message': 'PR_TITLE', 'merge_commit_title': 'MERGE_MESSAGE'}}, 'base': {'label': 'dolphin-emu:master', 'ref': 'master', 'sha': 'd3b2943807dd0073f7767947466dd73cccfef319', 'user': {'login': 'dolphin-emu', 'id': 5050316, 'node_id': 'MDEyOk9yZ2FuaXphdGlvbjUwNTAzMTY=', 'avatar_url': 'https://avatars.githubusercontent.com/u/5050316?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/dolphin-emu', 'html_url': 'https://github.com/dolphin-emu', 'followers_url': 'https://api.github.com/users/dolphin-emu/followers', 'following_url': 'https://api.github.com/users/dolphin-emu/following{/other_user}', 'gists_url': 'https://api.github.com/users/dolphin-emu/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/dolphin-emu/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/dolphin-emu/subscriptions', 'organizations_url': 'https://api.github.com/users/dolphin-emu/orgs', 'repos_url': 'https://api.github.com/users/dolphin-emu/repos', 'events_url': 'https://api.github.com/users/dolphin-emu/events{/privacy}', 'received_events_url': 'https://api.github.com/users/dolphin-emu/received_events', 'type': 'Organization', 'user_view_type': 'public', 'site_admin': False}, 'repo': {'id': 11577304, 'node_id': 'MDEwOlJlcG9zaXRvcnkxMTU3NzMwNA==', 'name': 'dolphin', 'full_name': 'dolphin-emu/dolphin', 'private': False, 'owner': {'login': 'dolphin-emu', 'id': 5050316, 'node_id': 'MDEyOk9yZ2FuaXphdGlvbjUwNTAzMTY=', 'avatar_url': 'https://avatars.githubusercontent.com/u/5050316?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/dolphin-emu', 'html_url': 'https://github.com/dolphin-emu', 'followers_url': 'https://api.github.com/users/dolphin-emu/followers', 'following_url': 'https://api.github.com/users/dolphin-emu/following{/other_user}', 'gists_url': 'https://api.github.com/users/dolphin-emu/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/dolphin-emu/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/dolphin-emu/subscriptions', 'organizations_url': 'https://api.github.com/users/dolphin-emu/orgs', 'repos_url': 'https://api.github.com/users/dolphin-emu/repos', 'events_url': 'https://api.github.com/users/dolphin-emu/events{/privacy}', 'received_events_url': 'https://api.github.com/users/dolphin-emu/received_events', 'type': 'Organization', 'user_view_type': 'public', 'site_admin': False}, 'html_url': 'https://github.com/dolphin-emu/dolphin', 'description': 'Dolphin is a GameCube / Wii emulator, allowing you to play games for these two platforms on PC with improvements.', 'fork': False, 'url': 'https://api.github.com/repos/dolphin-emu/dolphin', 'forks_url': 'https://api.github.com/repos/dolphin-emu/dolphin/forks', 'keys_url': 'https://api.github.com/repos/dolphin-emu/dolphin/keys{/key_id}', 'collaborators_url': 'https://api.github.com/repos/dolphin-emu/dolphin/collaborators{/collaborator}', 'teams_url': 'https://api.github.com/repos/dolphin-emu/dolphin/teams', 'hooks_url': 'https://api.github.com/repos/dolphin-emu/dolphin/hooks', 'issue_events_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/events{/number}', 'events_url': 'https://api.github.com/repos/dolphin-emu/dolphin/events', 'assignees_url': 'https://api.github.com/repos/dolphin-emu/dolphin/assignees{/user}', 'branches_url': 'https://api.github.com/repos/dolphin-emu/dolphin/branches{/branch}', 'tags_url': 'https://api.github.com/repos/dolphin-emu/dolphin/tags', 'blobs_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/blobs{/sha}', 'git_tags_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/tags{/sha}', 'git_refs_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/refs{/sha}', 'trees_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/trees{/sha}', 'statuses_url': 'https://api.github.com/repos/dolphin-emu/dolphin/statuses/{sha}', 'languages_url': 'https://api.github.com/repos/dolphin-emu/dolphin/languages', 'stargazers_url': 'https://api.github.com/repos/dolphin-emu/dolphin/stargazers', 'contributors_url': 'https://api.github.com/repos/dolphin-emu/dolphin/contributors', 'subscribers_url': 'https://api.github.com/repos/dolphin-emu/dolphin/subscribers', 'subscription_url': 'https://api.github.com/repos/dolphin-emu/dolphin/subscription', 'commits_url': 'https://api.github.com/repos/dolphin-emu/dolphin/commits{/sha}', 'git_commits_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/commits{/sha}', 'comments_url': 'https://api.github.com/repos/dolphin-emu/dolphin/comments{/number}', 'issue_comment_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/comments{/number}', 'contents_url': 'https://api.github.com/repos/dolphin-emu/dolphin/contents/{+path}', 'compare_url': 'https://api.github.com/repos/dolphin-emu/dolphin/compare/{base}...{head}', 'merges_url': 'https://api.github.com/repos/dolphin-emu/dolphin/merges', 'archive_url': 'https://api.github.com/repos/dolphin-emu/dolphin/{archive_format}{/ref}', 'downloads_url': 'https://api.github.com/repos/dolphin-emu/dolphin/downloads', 'issues_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues{/number}', 'pulls_url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls{/number}', 'milestones_url': 'https://api.github.com/repos/dolphin-emu/dolphin/milestones{/number}', 'notifications_url': 'https://api.github.com/repos/dolphin-emu/dolphin/notifications{?since,all,participating}', 'labels_url': 'https://api.github.com/repos/dolphin-emu/dolphin/labels{/name}', 'releases_url': 'https://api.github.com/repos/dolphin-emu/dolphin/releases{/id}', 'deployments_url': 'https://api.github.com/repos/dolphin-emu/dolphin/deployments', 'created_at': '2013-07-22T09:07:57Z', 'updated_at': '2026-07-18T23:13:54Z', 'pushed_at': '2026-07-18T10:34:54Z', 'git_url': 'git://github.com/dolphin-emu/dolphin.git', 'ssh_url': 'git@github.com:dolphin-emu/dolphin.git', 'clone_url': 'https://github.com/dolphin-emu/dolphin.git', 'svn_url': 'https://github.com/dolphin-emu/dolphin', 'homepage': 'https://dolphin-emu.org', 'size': 558448, 'stargazers_count': 15273, 'watchers_count': 15273, 'language': 'C++', 'has_issues': False, 'has_projects': False, 'has_downloads': True, 'has_wiki': True, 'has_pages': False, 'has_discussions': False, 'forks_count': 3162, 'mirror_url': None, 'archived': False, 'disabled': False, 'open_issues_count': 446, 'license': {'key': 'other', 'name': 'Other', 'spdx_id': 'NOASSERTION', 'url': None, 'node_id': 'MDc6TGljZW5zZTA='}, 'allow_forking': True, 'is_template': False, 'web_commit_signoff_required': False, 'has_pull_requests': True, 'pull_request_creation_policy': 'all', 'topics': ['cpp', 'emulation', 'emulator', 'gamecube', 'wii'], 'visibility': 'public', 'forks': 3162, 'open_issues': 446, 'watchers': 15273, 'default_branch': 'master', 'allow_squash_merge': False, 'allow_merge_commit': True, 'allow_rebase_merge': False, 'allow_auto_merge': False, 'delete_branch_on_merge': False, 'allow_update_branch': False, 'use_squash_pr_title_as_default': False, 'squash_merge_commit_message': 'COMMIT_MESSAGES', 'squash_merge_commit_title': 'COMMIT_OR_PR_TITLE', 'merge_commit_message': 'PR_TITLE', 'merge_commit_title': 'MERGE_MESSAGE'}}, '_links': {'self': {'href': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/14731'}, 'html': {'href': 'https://github.com/dolphin-emu/dolphin/pull/14731'}, 'issue': {'href': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/14731'}, 'comments': {'href': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/14731/comments'}, 'review_comments': {'href': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/14731/comments'}, 'review_comment': {'href': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/comments{/number}'}, 'commits': {'href': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/14731/commits'}, 'statuses': {'href': 'https://api.github.com/repos/dolphin-emu/dolphin/statuses/24b41d58df2315831b74f76b95417f2739d02f9d'}}, 'author_association': 'NONE', 'auto_merge': None, 'assignee': None, 'active_lock_reason': None}, 'repository': {'id': 11577304, 'node_id': 'MDEwOlJlcG9zaXRvcnkxMTU3NzMwNA==', 'name': 'dolphin', 'full_name': 'dolphin-emu/dolphin', 'private': False, 'owner': {'login': 'dolphin-emu', 'id': 5050316, 'node_id': 'MDEyOk9yZ2FuaXphdGlvbjUwNTAzMTY=', 'avatar_url': 'https://avatars.githubusercontent.com/u/5050316?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/dolphin-emu', 'html_url': 'https://github.com/dolphin-emu', 'followers_url': 'https://api.github.com/users/dolphin-emu/followers', 'following_url': 'https://api.github.com/users/dolphin-emu/following{/other_user}', 'gists_url': 'https://api.github.com/users/dolphin-emu/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/dolphin-emu/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/dolphin-emu/subscriptions', 'organizations_url': 'https://api.github.com/users/dolphin-emu/orgs', 'repos_url': 'https://api.github.com/users/dolphin-emu/repos', 'events_url': 'https://api.github.com/users/dolphin-emu/events{/privacy}', 'received_events_url': 'https://api.github.com/users/dolphin-emu/received_events', 'type': 'Organization', 'user_view_type': 'public', 'site_admin': False}, 'html_url': 'https://github.com/dolphin-emu/dolphin', 'description': 'Dolphin is a GameCube / Wii emulator, allowing you to play games for these two platforms on PC with improvements.', 'fork': False, 'url': 'https://api.github.com/repos/dolphin-emu/dolphin', 'forks_url': 'https://api.github.com/repos/dolphin-emu/dolphin/forks', 'keys_url': 'https://api.github.com/repos/dolphin-emu/dolphin/keys{/key_id}', 'collaborators_url': 'https://api.github.com/repos/dolphin-emu/dolphin/collaborators{/collaborator}', 'teams_url': 'https://api.github.com/repos/dolphin-emu/dolphin/teams', 'hooks_url': 'https://api.github.com/repos/dolphin-emu/dolphin/hooks', 'issue_events_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/events{/number}', 'events_url': 'https://api.github.com/repos/dolphin-emu/dolphin/events', 'assignees_url': 'https://api.github.com/repos/dolphin-emu/dolphin/assignees{/user}', 'branches_url': 'https://api.github.com/repos/dolphin-emu/dolphin/branches{/branch}', 'tags_url': 'https://api.github.com/repos/dolphin-emu/dolphin/tags', 'blobs_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/blobs{/sha}', 'git_tags_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/tags{/sha}', 'git_refs_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/refs{/sha}', 'trees_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/trees{/sha}', 'statuses_url': 'https://api.github.com/repos/dolphin-emu/dolphin/statuses/{sha}', 'languages_url': 'https://api.github.com/repos/dolphin-emu/dolphin/languages', 'stargazers_url': 'https://api.github.com/repos/dolphin-emu/dolphin/stargazers', 'contributors_url': 'https://api.github.com/repos/dolphin-emu/dolphin/contributors', 'subscribers_url': 'https://api.github.com/repos/dolphin-emu/dolphin/subscribers', 'subscription_url': 'https://api.github.com/repos/dolphin-emu/dolphin/subscription', 'commits_url': 'https://api.github.com/repos/dolphin-emu/dolphin/commits{/sha}', 'git_commits_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/commits{/sha}', 'comments_url': 'https://api.github.com/repos/dolphin-emu/dolphin/comments{/number}', 'issue_comment_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/comments{/number}', 'contents_url': 'https://api.github.com/repos/dolphin-emu/dolphin/contents/{+path}', 'compare_url': 'https://api.github.com/repos/dolphin-emu/dolphin/compare/{base}...{head}', 'merges_url': 'https://api.github.com/repos/dolphin-emu/dolphin/merges', 'archive_url': 'https://api.github.com/repos/dolphin-emu/dolphin/{archive_format}{/ref}', 'downloads_url': 'https://api.github.com/repos/dolphin-emu/dolphin/downloads', 'issues_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues{/number}', 'pulls_url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls{/number}', 'milestones_url': 'https://api.github.com/repos/dolphin-emu/dolphin/milestones{/number}', 'notifications_url': 'https://api.github.com/repos/dolphin-emu/dolphin/notifications{?since,all,participating}', 'labels_url': 'https://api.github.com/repos/dolphin-emu/dolphin/labels{/name}', 'releases_url': 'https://api.github.com/repos/dolphin-emu/dolphin/releases{/id}', 'deployments_url': 'https://api.github.com/repos/dolphin-emu/dolphin/deployments', 'created_at': '2013-07-22T09:07:57Z', 'updated_at': '2026-07-18T23:13:54Z', 'pushed_at': '2026-07-18T10:34:54Z', 'git_url': 'git://github.com/dolphin-emu/dolphin.git', 'ssh_url': 'git@github.com:dolphin-emu/dolphin.git', 'clone_url': 'https://github.com/dolphin-emu/dolphin.git', 'svn_url': 'https://github.com/dolphin-emu/dolphin', 'homepage': 'https://dolphin-emu.org', 'size': 558448, 'stargazers_count': 15273, 'watchers_count': 15273, 'language': 'C++', 'has_issues': False, 'has_projects': False, 'has_downloads': True, 'has_wiki': True, 'has_pages': False, 'has_discussions': False, 'forks_count': 3162, 'mirror_url': None, 'archived': False, 'disabled': False, 'open_issues_count': 446, 'license': {'key': 'other', 'name': 'Other', 'spdx_id': 'NOASSERTION', 'url': None, 'node_id': 'MDc6TGljZW5zZTA='}, 'allow_forking': True, 'is_template': False, 'web_commit_signoff_required': False, 'has_pull_requests': True, 'pull_request_creation_policy': 'all', 'topics': ['cpp', 'emulation', 'emulator', 'gamecube', 'wii'], 'visibility': 'public', 'forks': 3162, 'open_issues': 446, 'watchers': 15273, 'default_branch': 'master', 'custom_properties': {}}, 'organization': {'login': 'dolphin-emu', 'id': 5050316, 'node_id': 'MDEyOk9yZ2FuaXphdGlvbjUwNTAzMTY=', 'url': 'https://api.github.com/orgs/dolphin-emu', 'repos_url': 'https://api.github.com/orgs/dolphin-emu/repos', 'events_url': 'https://api.github.com/orgs/dolphin-emu/events', 'hooks_url': 'https://api.github.com/orgs/dolphin-emu/hooks', 'issues_url': 'https://api.github.com/orgs/dolphin-emu/issues', 'members_url': 'https://api.github.com/orgs/dolphin-emu/members{/member}', 'public_members_url': 'https://api.github.com/orgs/dolphin-emu/public_members{/member}', 'avatar_url': 'https://avatars.githubusercontent.com/u/5050316?v=4', 'description': ''}, 'sender': {'login': 'thethiny', 'id': 6018214, 'node_id': 'MDQ6VXNlcjYwMTgyMTQ=', 'avatar_url': 'https://avatars.githubusercontent.com/u/6018214?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/thethiny', 'html_url': 'https://github.com/thethiny', 'followers_url': 'https://api.github.com/users/thethiny/followers', 'following_url': 'https://api.github.com/users/thethiny/following{/other_user}', 'gists_url': 'https://api.github.com/users/thethiny/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/thethiny/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/thethiny/subscriptions', 'organizations_url': 'https://api.github.com/users/thethiny/orgs', 'repos_url': 'https://api.github.com/users/thethiny/repos', 'events_url': 'https://api.github.com/users/thethiny/events{/privacy}', 'received_events_url': 'https://api.github.com/users/thethiny/received_events', 'type': 'User', 'user_view_type': 'public', 'site_admin': False}, 'installation': {'id': 35437981, 'node_id': 'MDIzOkludGVncmF0aW9uSW5zdGFsbGF0aW9uMzU0Mzc5ODE='}}, 'type': 'raw_gh_hook'}
2026-07-18T23:37:37.379719	{'source': 'webserver', 'gh_type': 'pull_request_review', 'raw': {'action': 'submitted', 'review': {'id': 4729501733, 'node_id': 'PRR_kwDOALCn2M8AAAABGeZ4JQ', 'user': {'login': 'thethiny', 'id': 6018214, 'node_id': 'MDQ6VXNlcjYwMTgyMTQ=', 'avatar_url': 'https://avatars.githubusercontent.com/u/6018214?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/thethiny', 'html_url': 'https://github.com/thethiny', 'followers_url': 'https://api.github.com/users/thethiny/followers', 'following_url': 'https://api.github.com/users/thethiny/following{/other_user}', 'gists_url': 'https://api.github.com/users/thethiny/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/thethiny/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/thethiny/subscriptions', 'organizations_url': 'https://api.github.com/users/thethiny/orgs', 'repos_url': 'https://api.github.com/users/thethiny/repos', 'events_url': 'https://api.github.com/users/thethiny/events{/privacy}', 'received_events_url': 'https://api.github.com/users/thethiny/received_events', 'type': 'User', 'user_view_type': 'public', 'site_admin': False}, 'body': None, 'commit_id': '24b41d58df2315831b74f76b95417f2739d02f9d', 'state': 'commented', 'html_url': 'https://github.com/dolphin-emu/dolphin/pull/14731#pullrequestreview-4729501733', 'pull_request_url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/14731', '_links': {'html': {'href': 'https://github.com/dolphin-emu/dolphin/pull/14731#pullrequestreview-4729501733'}, 'pull_request': {'href': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/14731'}}, 'submitted_at': '2026-07-18T23:37:35Z', 'updated_at': '2026-07-18T23:37:35Z', 'author_association': 'NONE'}, 'pull_request': {'url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/14731', 'id': 4056977334, 'node_id': 'PR_kwDOALCn2M7x0I-2', 'html_url': 'https://github.com/dolphin-emu/dolphin/pull/14731', 'diff_url': 'https://github.com/dolphin-emu/dolphin/pull/14731.diff', 'patch_url': 'https://github.com/dolphin-emu/dolphin/pull/14731.patch', 'issue_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/14731', 'number': 14731, 'state': 'open', 'locked': False, 'title': 'Convert To WBFS Support', 'user': {'login': 'thethiny', 'id': 6018214, 'node_id': 'MDQ6VXNlcjYwMTgyMTQ=', 'avatar_url': 'https://avatars.githubusercontent.com/u/6018214?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/thethiny', 'html_url': 'https://github.com/thethiny', 'followers_url': 'https://api.github.com/users/thethiny/followers', 'following_url': 'https://api.github.com/users/thethiny/following{/other_user}', 'gists_url': 'https://api.github.com/users/thethiny/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/thethiny/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/thethiny/subscriptions', 'organizations_url': 'https://api.github.com/users/thethiny/orgs', 'repos_url': 'https://api.github.com/users/thethiny/repos', 'events_url': 'https://api.github.com/users/thethiny/events{/privacy}', 'received_events_url': 'https://api.github.com/users/thethiny/received_events', 'type': 'User', 'user_view_type': 'public', 'site_admin': False}, 'body': "This PR introduces Conversion **to** WBFS support. WBFS is the format that is used by USB Loaders on a real Wii device.\r\n\r\n## Design decisions & hardcoded values\r\nThe writer uses fixed sector sizes that match what [libwbfs (the reference implementation by kwiirk)](https://github.com/kwiirk/wbfs/blob/master/libwbfs/libwbfs.c#L128-L134) computes for a standard single-layer Wii disc. These 2 hardcodes are stable and work correctly across all my testings.\r\n- HD sector shift: 9 (512 bytes)\r\n- WBFS sector shift: 21 (2 MiB)\r\nThese are not configurable via the UI. All existing WBFS tools use these values, and since the aim is to support USB Loaders then this has been tested and it is working on a real Wii.\r\n\r\nConverting from WBFS is not enabled. The existing `WbfsFileReader` reports `DataSizeType::UpperBound`, and `ShouldAllowConversion()` requires `Accurate`. I am able to support this but since it was hardcoded by the Dolphin team I thought a discussion is warranted.\r\n\r\n## Testing\r\n- Verified with DolphinTool header and DolphinTool verify\r\n- Verified with wit FILETYPE and wit DUMP (Wiimm's ISO Tools recognizes valid WBFS structure, partitions, encryption)\r\n- Tested ISO to WBFS and RVZ to WBFS conversions\r\n- Output file sizes match Wii Backup Manager when scrubbing is enabled (~0.1% difference), works when scrubbing is disabled.\r\n- Output WBFS files play correctly in Dolphin\r\n- Output WBFS files play correctly on a real Wii using USB Loader GX e25c4f3\r\n", 'created_at': '2026-07-15T01:16:25Z', 'updated_at': '2026-07-18T23:36:11Z', 'closed_at': None, 'merged_at': None, 'merge_commit_sha': '228f93416dd80eb09da834ad7852c8eaa4d9212b', 'assignees': [], 'requested_reviewers': [], 'requested_teams': [], 'labels': [], 'milestone': None, 'draft': False, 'commits_url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/14731/commits', 'review_comments_url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/14731/comments', 'review_comment_url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/comments{/number}', 'comments_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/14731/comments', 'statuses_url': 'https://api.github.com/repos/dolphin-emu/dolphin/statuses/24b41d58df2315831b74f76b95417f2739d02f9d', 'head': {'label': 'thethiny:wbfs-conversion', 'ref': 'wbfs-conversion', 'sha': '24b41d58df2315831b74f76b95417f2739d02f9d', 'user': {'login': 'thethiny', 'id': 6018214, 'node_id': 'MDQ6VXNlcjYwMTgyMTQ=', 'avatar_url': 'https://avatars.githubusercontent.com/u/6018214?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/thethiny', 'html_url': 'https://github.com/thethiny', 'followers_url': 'https://api.github.com/users/thethiny/followers', 'following_url': 'https://api.github.com/users/thethiny/following{/other_user}', 'gists_url': 'https://api.github.com/users/thethiny/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/thethiny/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/thethiny/subscriptions', 'organizations_url': 'https://api.github.com/users/thethiny/orgs', 'repos_url': 'https://api.github.com/users/thethiny/repos', 'events_url': 'https://api.github.com/users/thethiny/events{/privacy}', 'received_events_url': 'https://api.github.com/users/thethiny/received_events', 'type': 'User', 'user_view_type': 'public', 'site_admin': False}, 'repo': {'id': 1298654395, 'node_id': 'R_kgDOTWfkuw', 'name': 'dolphin', 'full_name': 'thethiny/dolphin', 'private': False, 'owner': {'login': 'thethiny', 'id': 6018214, 'node_id': 'MDQ6VXNlcjYwMTgyMTQ=', 'avatar_url': 'https://avatars.githubusercontent.com/u/6018214?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/thethiny', 'html_url': 'https://github.com/thethiny', 'followers_url': 'https://api.github.com/users/thethiny/followers', 'following_url': 'https://api.github.com/users/thethiny/following{/other_user}', 'gists_url': 'https://api.github.com/users/thethiny/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/thethiny/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/thethiny/subscriptions', 'organizations_url': 'https://api.github.com/users/thethiny/orgs', 'repos_url': 'https://api.github.com/users/thethiny/repos', 'events_url': 'https://api.github.com/users/thethiny/events{/privacy}', 'received_events_url': 'https://api.github.com/users/thethiny/received_events', 'type': 'User', 'user_view_type': 'public', 'site_admin': False}, 'html_url': 'https://github.com/thethiny/dolphin', 'description': 'Dolphin is a GameCube / Wii emulator, allowing you to play games for these two platforms on PC with improvements.', 'fork': True, 'url': 'https://api.github.com/repos/thethiny/dolphin', 'forks_url': 'https://api.github.com/repos/thethiny/dolphin/forks', 'keys_url': 'https://api.github.com/repos/thethiny/dolphin/keys{/key_id}', 'collaborators_url': 'https://api.github.com/repos/thethiny/dolphin/collaborators{/collaborator}', 'teams_url': 'https://api.github.com/repos/thethiny/dolphin/teams', 'hooks_url': 'https://api.github.com/repos/thethiny/dolphin/hooks', 'issue_events_url': 'https://api.github.com/repos/thethiny/dolphin/issues/events{/number}', 'events_url': 'https://api.github.com/repos/thethiny/dolphin/events', 'assignees_url': 'https://api.github.com/repos/thethiny/dolphin/assignees{/user}', 'branches_url': 'https://api.github.com/repos/thethiny/dolphin/branches{/branch}', 'tags_url': 'https://api.github.com/repos/thethiny/dolphin/tags', 'blobs_url': 'https://api.github.com/repos/thethiny/dolphin/git/blobs{/sha}', 'git_tags_url': 'https://api.github.com/repos/thethiny/dolphin/git/tags{/sha}', 'git_refs_url': 'https://api.github.com/repos/thethiny/dolphin/git/refs{/sha}', 'trees_url': 'https://api.github.com/repos/thethiny/dolphin/git/trees{/sha}', 'statuses_url': 'https://api.github.com/repos/thethiny/dolphin/statuses/{sha}', 'languages_url': 'https://api.github.com/repos/thethiny/dolphin/languages', 'stargazers_url': 'https://api.github.com/repos/thethiny/dolphin/stargazers', 'contributors_url': 'https://api.github.com/repos/thethiny/dolphin/contributors', 'subscribers_url': 'https://api.github.com/repos/thethiny/dolphin/subscribers', 'subscription_url': 'https://api.github.com/repos/thethiny/dolphin/subscription', 'commits_url': 'https://api.github.com/repos/thethiny/dolphin/commits{/sha}', 'git_commits_url': 'https://api.github.com/repos/thethiny/dolphin/git/commits{/sha}', 'comments_url': 'https://api.github.com/repos/thethiny/dolphin/comments{/number}', 'issue_comment_url': 'https://api.github.com/repos/thethiny/dolphin/issues/comments{/number}', 'contents_url': 'https://api.github.com/repos/thethiny/dolphin/contents/{+path}', 'compare_url': 'https://api.github.com/repos/thethiny/dolphin/compare/{base}...{head}', 'merges_url': 'https://api.github.com/repos/thethiny/dolphin/merges', 'archive_url': 'https://api.github.com/repos/thethiny/dolphin/{archive_format}{/ref}', 'downloads_url': 'https://api.github.com/repos/thethiny/dolphin/downloads', 'issues_url': 'https://api.github.com/repos/thethiny/dolphin/issues{/number}', 'pulls_url': 'https://api.github.com/repos/thethiny/dolphin/pulls{/number}', 'milestones_url': 'https://api.github.com/repos/thethiny/dolphin/milestones{/number}', 'notifications_url': 'https://api.github.com/repos/thethiny/dolphin/notifications{?since,all,participating}', 'labels_url': 'https://api.github.com/repos/thethiny/dolphin/labels{/name}', 'releases_url': 'https://api.github.com/repos/thethiny/dolphin/releases{/id}', 'deployments_url': 'https://api.github.com/repos/thethiny/dolphin/deployments', 'created_at': '2026-07-12T22:09:13Z', 'updated_at': '2026-07-12T22:09:13Z', 'pushed_at': '2026-07-18T20:35:03Z', 'git_url': 'git://github.com/thethiny/dolphin.git', 'ssh_url': 'git@github.com:thethiny/dolphin.git', 'clone_url': 'https://github.com/thethiny/dolphin.git', 'svn_url': 'https://github.com/thethiny/dolphin', 'homepage': 'https://dolphin-emu.org', 'size': 515471, 'stargazers_count': 0, 'watchers_count': 0, 'language': None, 'has_issues': False, 'has_projects': True, 'has_downloads': True, 'has_wiki': True, 'has_pages': False, 'has_discussions': False, 'forks_count': 0, 'mirror_url': None, 'archived': False, 'disabled': False, 'open_issues_count': 0, 'license': {'key': 'other', 'name': 'Other', 'spdx_id': 'NOASSERTION', 'url': None, 'node_id': 'MDc6TGljZW5zZTA='}, 'allow_forking': True, 'is_template': False, 'web_commit_signoff_required': False, 'has_pull_requests': True, 'pull_request_creation_policy': 'all', 'topics': [], 'visibility': 'public', 'forks': 0, 'open_issues': 0, 'watchers': 0, 'default_branch': 'master', 'allow_squash_merge': True, 'allow_merge_commit': True, 'allow_rebase_merge': True, 'allow_auto_merge': False, 'delete_branch_on_merge': False, 'allow_update_branch': False, 'use_squash_pr_title_as_default': False, 'squash_merge_commit_message': 'COMMIT_MESSAGES', 'squash_merge_commit_title': 'COMMIT_OR_PR_TITLE', 'merge_commit_message': 'PR_TITLE', 'merge_commit_title': 'MERGE_MESSAGE'}}, 'base': {'label': 'dolphin-emu:master', 'ref': 'master', 'sha': 'd3b2943807dd0073f7767947466dd73cccfef319', 'user': {'login': 'dolphin-emu', 'id': 5050316, 'node_id': 'MDEyOk9yZ2FuaXphdGlvbjUwNTAzMTY=', 'avatar_url': 'https://avatars.githubusercontent.com/u/5050316?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/dolphin-emu', 'html_url': 'https://github.com/dolphin-emu', 'followers_url': 'https://api.github.com/users/dolphin-emu/followers', 'following_url': 'https://api.github.com/users/dolphin-emu/following{/other_user}', 'gists_url': 'https://api.github.com/users/dolphin-emu/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/dolphin-emu/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/dolphin-emu/subscriptions', 'organizations_url': 'https://api.github.com/users/dolphin-emu/orgs', 'repos_url': 'https://api.github.com/users/dolphin-emu/repos', 'events_url': 'https://api.github.com/users/dolphin-emu/events{/privacy}', 'received_events_url': 'https://api.github.com/users/dolphin-emu/received_events', 'type': 'Organization', 'user_view_type': 'public', 'site_admin': False}, 'repo': {'id': 11577304, 'node_id': 'MDEwOlJlcG9zaXRvcnkxMTU3NzMwNA==', 'name': 'dolphin', 'full_name': 'dolphin-emu/dolphin', 'private': False, 'owner': {'login': 'dolphin-emu', 'id': 5050316, 'node_id': 'MDEyOk9yZ2FuaXphdGlvbjUwNTAzMTY=', 'avatar_url': 'https://avatars.githubusercontent.com/u/5050316?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/dolphin-emu', 'html_url': 'https://github.com/dolphin-emu', 'followers_url': 'https://api.github.com/users/dolphin-emu/followers', 'following_url': 'https://api.github.com/users/dolphin-emu/following{/other_user}', 'gists_url': 'https://api.github.com/users/dolphin-emu/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/dolphin-emu/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/dolphin-emu/subscriptions', 'organizations_url': 'https://api.github.com/users/dolphin-emu/orgs', 'repos_url': 'https://api.github.com/users/dolphin-emu/repos', 'events_url': 'https://api.github.com/users/dolphin-emu/events{/privacy}', 'received_events_url': 'https://api.github.com/users/dolphin-emu/received_events', 'type': 'Organization', 'user_view_type': 'public', 'site_admin': False}, 'html_url': 'https://github.com/dolphin-emu/dolphin', 'description': 'Dolphin is a GameCube / Wii emulator, allowing you to play games for these two platforms on PC with improvements.', 'fork': False, 'url': 'https://api.github.com/repos/dolphin-emu/dolphin', 'forks_url': 'https://api.github.com/repos/dolphin-emu/dolphin/forks', 'keys_url': 'https://api.github.com/repos/dolphin-emu/dolphin/keys{/key_id}', 'collaborators_url': 'https://api.github.com/repos/dolphin-emu/dolphin/collaborators{/collaborator}', 'teams_url': 'https://api.github.com/repos/dolphin-emu/dolphin/teams', 'hooks_url': 'https://api.github.com/repos/dolphin-emu/dolphin/hooks', 'issue_events_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/events{/number}', 'events_url': 'https://api.github.com/repos/dolphin-emu/dolphin/events', 'assignees_url': 'https://api.github.com/repos/dolphin-emu/dolphin/assignees{/user}', 'branches_url': 'https://api.github.com/repos/dolphin-emu/dolphin/branches{/branch}', 'tags_url': 'https://api.github.com/repos/dolphin-emu/dolphin/tags', 'blobs_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/blobs{/sha}', 'git_tags_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/tags{/sha}', 'git_refs_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/refs{/sha}', 'trees_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/trees{/sha}', 'statuses_url': 'https://api.github.com/repos/dolphin-emu/dolphin/statuses/{sha}', 'languages_url': 'https://api.github.com/repos/dolphin-emu/dolphin/languages', 'stargazers_url': 'https://api.github.com/repos/dolphin-emu/dolphin/stargazers', 'contributors_url': 'https://api.github.com/repos/dolphin-emu/dolphin/contributors', 'subscribers_url': 'https://api.github.com/repos/dolphin-emu/dolphin/subscribers', 'subscription_url': 'https://api.github.com/repos/dolphin-emu/dolphin/subscription', 'commits_url': 'https://api.github.com/repos/dolphin-emu/dolphin/commits{/sha}', 'git_commits_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/commits{/sha}', 'comments_url': 'https://api.github.com/repos/dolphin-emu/dolphin/comments{/number}', 'issue_comment_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/comments{/number}', 'contents_url': 'https://api.github.com/repos/dolphin-emu/dolphin/contents/{+path}', 'compare_url': 'https://api.github.com/repos/dolphin-emu/dolphin/compare/{base}...{head}', 'merges_url': 'https://api.github.com/repos/dolphin-emu/dolphin/merges', 'archive_url': 'https://api.github.com/repos/dolphin-emu/dolphin/{archive_format}{/ref}', 'downloads_url': 'https://api.github.com/repos/dolphin-emu/dolphin/downloads', 'issues_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues{/number}', 'pulls_url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls{/number}', 'milestones_url': 'https://api.github.com/repos/dolphin-emu/dolphin/milestones{/number}', 'notifications_url': 'https://api.github.com/repos/dolphin-emu/dolphin/notifications{?since,all,participating}', 'labels_url': 'https://api.github.com/repos/dolphin-emu/dolphin/labels{/name}', 'releases_url': 'https://api.github.com/repos/dolphin-emu/dolphin/releases{/id}', 'deployments_url': 'https://api.github.com/repos/dolphin-emu/dolphin/deployments', 'created_at': '2013-07-22T09:07:57Z', 'updated_at': '2026-07-18T23:13:54Z', 'pushed_at': '2026-07-18T10:34:54Z', 'git_url': 'git://github.com/dolphin-emu/dolphin.git', 'ssh_url': 'git@github.com:dolphin-emu/dolphin.git', 'clone_url': 'https://github.com/dolphin-emu/dolphin.git', 'svn_url': 'https://github.com/dolphin-emu/dolphin', 'homepage': 'https://dolphin-emu.org', 'size': 558448, 'stargazers_count': 15273, 'watchers_count': 15273, 'language': 'C++', 'has_issues': False, 'has_projects': False, 'has_downloads': True, 'has_wiki': True, 'has_pages': False, 'has_discussions': False, 'forks_count': 3162, 'mirror_url': None, 'archived': False, 'disabled': False, 'open_issues_count': 446, 'license': {'key': 'other', 'name': 'Other', 'spdx_id': 'NOASSERTION', 'url': None, 'node_id': 'MDc6TGljZW5zZTA='}, 'allow_forking': True, 'is_template': False, 'web_commit_signoff_required': False, 'has_pull_requests': True, 'pull_request_creation_policy': 'all', 'topics': ['cpp', 'emulation', 'emulator', 'gamecube', 'wii'], 'visibility': 'public', 'forks': 3162, 'open_issues': 446, 'watchers': 15273, 'default_branch': 'master', 'allow_squash_merge': False, 'allow_merge_commit': True, 'allow_rebase_merge': False, 'allow_auto_merge': False, 'delete_branch_on_merge': False, 'allow_update_branch': False, 'use_squash_pr_title_as_default': False, 'squash_merge_commit_message': 'COMMIT_MESSAGES', 'squash_merge_commit_title': 'COMMIT_OR_PR_TITLE', 'merge_commit_message': 'PR_TITLE', 'merge_commit_title': 'MERGE_MESSAGE'}}, '_links': {'self': {'href': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/14731'}, 'html': {'href': 'https://github.com/dolphin-emu/dolphin/pull/14731'}, 'issue': {'href': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/14731'}, 'comments': {'href': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/14731/comments'}, 'review_comments': {'href': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/14731/comments'}, 'review_comment': {'href': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/comments{/number}'}, 'commits': {'href': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/14731/commits'}, 'statuses': {'href': 'https://api.github.com/repos/dolphin-emu/dolphin/statuses/24b41d58df2315831b74f76b95417f2739d02f9d'}}, 'author_association': 'NONE', 'auto_merge': None, 'assignee': None, 'active_lock_reason': None}, 'repository': {'id': 11577304, 'node_id': 'MDEwOlJlcG9zaXRvcnkxMTU3NzMwNA==', 'name': 'dolphin', 'full_name': 'dolphin-emu/dolphin', 'private': False, 'owner': {'login': 'dolphin-emu', 'id': 5050316, 'node_id': 'MDEyOk9yZ2FuaXphdGlvbjUwNTAzMTY=', 'avatar_url': 'https://avatars.githubusercontent.com/u/5050316?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/dolphin-emu', 'html_url': 'https://github.com/dolphin-emu', 'followers_url': 'https://api.github.com/users/dolphin-emu/followers', 'following_url': 'https://api.github.com/users/dolphin-emu/following{/other_user}', 'gists_url': 'https://api.github.com/users/dolphin-emu/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/dolphin-emu/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/dolphin-emu/subscriptions', 'organizations_url': 'https://api.github.com/users/dolphin-emu/orgs', 'repos_url': 'https://api.github.com/users/dolphin-emu/repos', 'events_url': 'https://api.github.com/users/dolphin-emu/events{/privacy}', 'received_events_url': 'https://api.github.com/users/dolphin-emu/received_events', 'type': 'Organization', 'user_view_type': 'public', 'site_admin': False}, 'html_url': 'https://github.com/dolphin-emu/dolphin', 'description': 'Dolphin is a GameCube / Wii emulator, allowing you to play games for these two platforms on PC with improvements.', 'fork': False, 'url': 'https://api.github.com/repos/dolphin-emu/dolphin', 'forks_url': 'https://api.github.com/repos/dolphin-emu/dolphin/forks', 'keys_url': 'https://api.github.com/repos/dolphin-emu/dolphin/keys{/key_id}', 'collaborators_url': 'https://api.github.com/repos/dolphin-emu/dolphin/collaborators{/collaborator}', 'teams_url': 'https://api.github.com/repos/dolphin-emu/dolphin/teams', 'hooks_url': 'https://api.github.com/repos/dolphin-emu/dolphin/hooks', 'issue_events_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/events{/number}', 'events_url': 'https://api.github.com/repos/dolphin-emu/dolphin/events', 'assignees_url': 'https://api.github.com/repos/dolphin-emu/dolphin/assignees{/user}', 'branches_url': 'https://api.github.com/repos/dolphin-emu/dolphin/branches{/branch}', 'tags_url': 'https://api.github.com/repos/dolphin-emu/dolphin/tags', 'blobs_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/blobs{/sha}', 'git_tags_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/tags{/sha}', 'git_refs_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/refs{/sha}', 'trees_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/trees{/sha}', 'statuses_url': 'https://api.github.com/repos/dolphin-emu/dolphin/statuses/{sha}', 'languages_url': 'https://api.github.com/repos/dolphin-emu/dolphin/languages', 'stargazers_url': 'https://api.github.com/repos/dolphin-emu/dolphin/stargazers', 'contributors_url': 'https://api.github.com/repos/dolphin-emu/dolphin/contributors', 'subscribers_url': 'https://api.github.com/repos/dolphin-emu/dolphin/subscribers', 'subscription_url': 'https://api.github.com/repos/dolphin-emu/dolphin/subscription', 'commits_url': 'https://api.github.com/repos/dolphin-emu/dolphin/commits{/sha}', 'git_commits_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/commits{/sha}', 'comments_url': 'https://api.github.com/repos/dolphin-emu/dolphin/comments{/number}', 'issue_comment_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/comments{/number}', 'contents_url': 'https://api.github.com/repos/dolphin-emu/dolphin/contents/{+path}', 'compare_url': 'https://api.github.com/repos/dolphin-emu/dolphin/compare/{base}...{head}', 'merges_url': 'https://api.github.com/repos/dolphin-emu/dolphin/merges', 'archive_url': 'https://api.github.com/repos/dolphin-emu/dolphin/{archive_format}{/ref}', 'downloads_url': 'https://api.github.com/repos/dolphin-emu/dolphin/downloads', 'issues_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues{/number}', 'pulls_url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls{/number}', 'milestones_url': 'https://api.github.com/repos/dolphin-emu/dolphin/milestones{/number}', 'notifications_url': 'https://api.github.com/repos/dolphin-emu/dolphin/notifications{?since,all,participating}', 'labels_url': 'https://api.github.com/repos/dolphin-emu/dolphin/labels{/name}', 'releases_url': 'https://api.github.com/repos/dolphin-emu/dolphin/releases{/id}', 'deployments_url': 'https://api.github.com/repos/dolphin-emu/dolphin/deployments', 'created_at': '2013-07-22T09:07:57Z', 'updated_at': '2026-07-18T23:13:54Z', 'pushed_at': '2026-07-18T10:34:54Z', 'git_url': 'git://github.com/dolphin-emu/dolphin.git', 'ssh_url': 'git@github.com:dolphin-emu/dolphin.git', 'clone_url': 'https://github.com/dolphin-emu/dolphin.git', 'svn_url': 'https://github.com/dolphin-emu/dolphin', 'homepage': 'https://dolphin-emu.org', 'size': 558448, 'stargazers_count': 15273, 'watchers_count': 15273, 'language': 'C++', 'has_issues': False, 'has_projects': False, 'has_downloads': True, 'has_wiki': True, 'has_pages': False, 'has_discussions': False, 'forks_count': 3162, 'mirror_url': None, 'archived': False, 'disabled': False, 'open_issues_count': 446, 'license': {'key': 'other', 'name': 'Other', 'spdx_id': 'NOASSERTION', 'url': None, 'node_id': 'MDc6TGljZW5zZTA='}, 'allow_forking': True, 'is_template': False, 'web_commit_signoff_required': False, 'has_pull_requests': True, 'pull_request_creation_policy': 'all', 'topics': ['cpp', 'emulation', 'emulator', 'gamecube', 'wii'], 'visibility': 'public', 'forks': 3162, 'open_issues': 446, 'watchers': 15273, 'default_branch': 'master', 'custom_properties': {}}, 'organization': {'login': 'dolphin-emu', 'id': 5050316, 'node_id': 'MDEyOk9yZ2FuaXphdGlvbjUwNTAzMTY=', 'url': 'https://api.github.com/orgs/dolphin-emu', 'repos_url': 'https://api.github.com/orgs/dolphin-emu/repos', 'events_url': 'https://api.github.com/orgs/dolphin-emu/events', 'hooks_url': 'https://api.github.com/orgs/dolphin-emu/hooks', 'issues_url': 'https://api.github.com/orgs/dolphin-emu/issues', 'members_url': 'https://api.github.com/orgs/dolphin-emu/members{/member}', 'public_members_url': 'https://api.github.com/orgs/dolphin-emu/public_members{/member}', 'avatar_url': 'https://avatars.githubusercontent.com/u/5050316?v=4', 'description': ''}, 'sender': {'login': 'thethiny', 'id': 6018214, 'node_id': 'MDQ6VXNlcjYwMTgyMTQ=', 'avatar_url': 'https://avatars.githubusercontent.com/u/6018214?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/thethiny', 'html_url': 'https://github.com/thethiny', 'followers_url': 'https://api.github.com/users/thethiny/followers', 'following_url': 'https://api.github.com/users/thethiny/following{/other_user}', 'gists_url': 'https://api.github.com/users/thethiny/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/thethiny/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/thethiny/subscriptions', 'organizations_url': 'https://api.github.com/users/thethiny/orgs', 'repos_url': 'https://api.github.com/users/thethiny/repos', 'events_url': 'https://api.github.com/users/thethiny/events{/privacy}', 'received_events_url': 'https://api.github.com/users/thethiny/received_events', 'type': 'User', 'user_view_type': 'public', 'site_admin': False}, 'installation': {'id': 35437981, 'node_id': 'MDIzOkludGVncmF0aW9uSW5zdGFsbGF0aW9uMzU0Mzc5ODE='}}, 'type': 'raw_gh_hook'}
2026-07-18T23:36:12.676814	{'source': 'webserver', 'gh_type': 'pull_request_review_comment', 'raw': {'action': 'created', 'comment': {'url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/comments/3609417157', 'pull_request_review_id': 4729499717, 'id': 3609417157, 'node_id': 'PRRC_kwDOALCn2M7XI1XF', 'diff_hunk': '@@ -119,22 +144,191 @@ bool WbfsFileReader::ReadHeader()\n   return m_header.disc_table[0] != 0;\n }\n \n+bool WbfsFileReader::ReadNKitHeader()\n+{\n+  const u64 gap_type_blocks = (DL_DVD_SIZE + m_wbfs_sector_size - 1) / m_wbfs_sector_size;\n+  m_nkit_info = NKit::ReadHeaderFromFile(m_files[0].file, NKit::HEADER_OFFSET, gap_type_blocks);\n+  if (!m_nkit_info.valid)\n+    return false;\n+\n+  m_has_nkit_header = true;\n+  return true;\n+}\n+\n+bool WbfsFileReader::IsBlockStored(u64 block_index) const\n+{\n+  return block_index < m_blocks_per_disc && m_wlba_table[block_index] != 0;\n+}\n+\n+bool WbfsFileReader::IsGapJunk(u64 block_index) const\n+{\n+  return NKit::IsGapJunk(m_nkit_info.gap_type, block_index);\n+}\n+\n+void WbfsFileReader::GenerateJunkData(u64 disc_offset, u64 size, u8* out) const\n+{\n+  LaggedFibonacciGenerator::FillJunkData(out, static_cast<size_t>(size), disc_offset, m_disc_id,\n+                                         m_disc_num);\n+}\n+\n+void WbfsFileReader::ReadPartitionInfo()\n+{\n+  std::unique_ptr<VolumeDisc> volume = CreateDisc(CopyReader());\n+  if (!volume)\n+    return;\n+\n+  for (const Partition& partition : volume->GetPartitions())\n+  {\n+    const auto& ticket = volume->GetTicket(partition);\n+    const std::array<u8, 16> title_key = ticket.GetTitleKey();\n+\n+    u8 data_info[8];\n+    if (!Read(partition.offset + 0x2B8, 8, data_info))\n+      continue;\n+\n+    PartitionEntry entry;\n+    entry.data_offset = partition.offset + (static_cast<u64>(Common::swap32(data_info)) << 2);\n+    entry.data_size = static_cast<u64>(Common::swap32(data_info + 4)) << 2;\n+    entry.key = title_key;\n+    m_partitions.push_back(entry);\n+  }\n+}\n+\n+const WbfsFileReader::PartitionEntry* WbfsFileReader::FindPartition(u64 disc_offset) const\n+{\n+  for (const auto& p : m_partitions)\n+  {\n+    if (disc_offset >= p.data_offset && disc_offset < p.data_offset + p.data_size)\n+      return &p;\n+  }\n+  return nullptr;\n+}\n+\n+const WbfsFileReader::PartitionEntry*\n+WbfsFileReader::FindPartitionByDataOffset(u64 partition_data_offset) const\n+{\n+  for (const auto& p : m_partitions)\n+  {\n+    if (p.data_offset == partition_data_offset)\n+      return &p;\n+  }\n+  return nullptr;\n+}\n+\n+bool WbfsFileReader::SupportsReadWiiDecrypted(u64 offset, u64 size, u64 partition_data_offset) const\n+{\n+  if (!m_has_nkit_header)\n+    return false;\n+\n+  const u64 block_in_partition = offset / VolumeWii::BLOCK_DATA_SIZE;\n+  const u64 disc_offset = partition_data_offset + block_in_partition * VolumeWii::BLOCK_TOTAL_SIZE;\n+  const u64 wbfs_block = disc_offset >> m_header.wbfs_sector_shift;\n+\n+  return wbfs_block < m_blocks_per_disc && !IsBlockStored(wbfs_block);\n+}\n+\n+bool WbfsFileReader::ReadWiiDecrypted(u64 offset, u64 size, u8* out_ptr, u64 partition_data_offset)\n+{\n+  const PartitionEntry* pe = FindPartitionByDataOffset(partition_data_offset);\n+  if (!pe)\n+    return false;\n+\n+  auto aes_ctx = Common::AES::CreateContextDecrypt(pe->key.data());\n+  std::vector<u8> encrypted(VolumeWii::BLOCK_TOTAL_SIZE);\n+  std::vector<u8> decrypted(VolumeWii::BLOCK_DATA_SIZE);\n+\n+  while (size > 0)\n+  {\n+    const u64 block_in_partition = offset / VolumeWii::BLOCK_DATA_SIZE;\n+    const u64 offset_in_block = offset % VolumeWii::BLOCK_DATA_SIZE;\n+    const u64 bytes_in_block = VolumeWii::BLOCK_DATA_SIZE - offset_in_block;\n+    const size_t read_size = static_cast<size_t>(std::min(bytes_in_block, size));\n+\n+    const u64 disc_offset =\n+        partition_data_offset + block_in_partition * VolumeWii::BLOCK_TOTAL_SIZE;\n+    const u64 wbfs_block = disc_offset >> m_header.wbfs_sector_shift;\n+\n+    if (IsBlockStored(wbfs_block))\n+    {\n+      u64 available;\n+      auto& file = SeekToCluster(disc_offset, &available);\n+      if (available < VolumeWii::BLOCK_TOTAL_SIZE ||\n+          !file.Read(encrypted.data(), VolumeWii::BLOCK_TOTAL_SIZE))\n+        return false;\n+      VolumeWii::DecryptBlockData(encrypted.data(), decrypted.data(), aes_ctx.get());\n+      std::memcpy(out_ptr, decrypted.data() + offset_in_block, read_size);\n+    }', 'path': 'Source/Core/DiscIO/WbfsBlob.cpp', 'commit_id': '24b41d58df2315831b74f76b95417f2739d02f9d', 'original_commit_id': '24b41d58df2315831b74f76b95417f2739d02f9d', 'user': {'login': 'thethiny', 'id': 6018214, 'node_id': 'MDQ6VXNlcjYwMTgyMTQ=', 'avatar_url': 'https://avatars.githubusercontent.com/u/6018214?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/thethiny', 'html_url': 'https://github.com/thethiny', 'followers_url': 'https://api.github.com/users/thethiny/followers', 'following_url': 'https://api.github.com/users/thethiny/following{/other_user}', 'gists_url': 'https://api.github.com/users/thethiny/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/thethiny/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/thethiny/subscriptions', 'organizations_url': 'https://api.github.com/users/thethiny/orgs', 'repos_url': 'https://api.github.com/users/thethiny/repos', 'events_url': 'https://api.github.com/users/thethiny/events{/privacy}', 'received_events_url': 'https://api.github.com/users/thethiny/received_events', 'type': 'User', 'user_view_type': 'public', 'site_admin': False}, 'body': 'This needs an investigation, since EncryptGroup processes about 64 sectors and therefore the sectors could be a mix of stored and non-stored blocks. It is possible that this path will never hit but I cannot confirm that since I did not test it out. I will do so and report back with either a fix or a result.', 'created_at': '2026-07-18T23:36:11Z', 'updated_at': '2026-07-18T23:36:11Z', 'html_url': 'https://github.com/dolphin-emu/dolphin/pull/14731#discussion_r3609417157', 'pull_request_url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/14731', '_links': {'self': {'href': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/comments/3609417157'}, 'html': {'href': 'https://github.com/dolphin-emu/dolphin/pull/14731#discussion_r3609417157'}, 'pull_request': {'href': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/14731'}}, 'reactions': {'url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/comments/3609417157/reactions', 'total_count': 0, '+1': 0, '-1': 0, 'laugh': 0, 'hooray': 0, 'confused': 0, 'heart': 0, 'rocket': 0, 'eyes': 0}, 'start_line': 251, 'original_start_line': 251, 'start_side': 'RIGHT', 'line': 260, 'original_line': 260, 'side': 'RIGHT', 'in_reply_to_id': 3609277919, 'author_association': 'NONE', 'original_position': 204, 'position': 204, 'subject_type': 'line'}, 'pull_request': {'url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/14731', 'id': 4056977334, 'node_id': 'PR_kwDOALCn2M7x0I-2', 'html_url': 'https://github.com/dolphin-emu/dolphin/pull/14731', 'diff_url': 'https://github.com/dolphin-emu/dolphin/pull/14731.diff', 'patch_url': 'https://github.com/dolphin-emu/dolphin/pull/14731.patch', 'issue_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/14731', 'number': 14731, 'state': 'open', 'locked': False, 'title': 'Convert To WBFS Support', 'user': {'login': 'thethiny', 'id': 6018214, 'node_id': 'MDQ6VXNlcjYwMTgyMTQ=', 'avatar_url': 'https://avatars.githubusercontent.com/u/6018214?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/thethiny', 'html_url': 'https://github.com/thethiny', 'followers_url': 'https://api.github.com/users/thethiny/followers', 'following_url': 'https://api.github.com/users/thethiny/following{/other_user}', 'gists_url': 'https://api.github.com/users/thethiny/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/thethiny/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/thethiny/subscriptions', 'organizations_url': 'https://api.github.com/users/thethiny/orgs', 'repos_url': 'https://api.github.com/users/thethiny/repos', 'events_url': 'https://api.github.com/users/thethiny/events{/privacy}', 'received_events_url': 'https://api.github.com/users/thethiny/received_events', 'type': 'User', 'user_view_type': 'public', 'site_admin': False}, 'body': "This PR introduces Conversion **to** WBFS support. WBFS is the format that is used by USB Loaders on a real Wii device.\r\n\r\n## Design decisions & hardcoded values\r\nThe writer uses fixed sector sizes that match what [libwbfs (the reference implementation by kwiirk)](https://github.com/kwiirk/wbfs/blob/master/libwbfs/libwbfs.c#L128-L134) computes for a standard single-layer Wii disc. These 2 hardcodes are stable and work correctly across all my testings.\r\n- HD sector shift: 9 (512 bytes)\r\n- WBFS sector shift: 21 (2 MiB)\r\nThese are not configurable via the UI. All existing WBFS tools use these values, and since the aim is to support USB Loaders then this has been tested and it is working on a real Wii.\r\n\r\nConverting from WBFS is not enabled. The existing `WbfsFileReader` reports `DataSizeType::UpperBound`, and `ShouldAllowConversion()` requires `Accurate`. I am able to support this but since it was hardcoded by the Dolphin team I thought a discussion is warranted.\r\n\r\n## Testing\r\n- Verified with DolphinTool header and DolphinTool verify\r\n- Verified with wit FILETYPE and wit DUMP (Wiimm's ISO Tools recognizes valid WBFS structure, partitions, encryption)\r\n- Tested ISO to WBFS and RVZ to WBFS conversions\r\n- Output file sizes match Wii Backup Manager when scrubbing is enabled (~0.1% difference), works when scrubbing is disabled.\r\n- Output WBFS files play correctly in Dolphin\r\n- Output WBFS files play correctly on a real Wii using USB Loader GX e25c4f3\r\n", 'created_at': '2026-07-15T01:16:25Z', 'updated_at': '2026-07-18T23:33:13Z', 'closed_at': None, 'merged_at': None, 'merge_commit_sha': '228f93416dd80eb09da834ad7852c8eaa4d9212b', 'assignees': [], 'requested_reviewers': [], 'requested_teams': [], 'labels': [], 'milestone': None, 'draft': False, 'commits_url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/14731/commits', 'review_comments_url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/14731/comments', 'review_comment_url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/comments{/number}', 'comments_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/14731/comments', 'statuses_url': 'https://api.github.com/repos/dolphin-emu/dolphin/statuses/24b41d58df2315831b74f76b95417f2739d02f9d', 'head': {'label': 'thethiny:wbfs-conversion', 'ref': 'wbfs-conversion', 'sha': '24b41d58df2315831b74f76b95417f2739d02f9d', 'user': {'login': 'thethiny', 'id': 6018214, 'node_id': 'MDQ6VXNlcjYwMTgyMTQ=', 'avatar_url': 'https://avatars.githubusercontent.com/u/6018214?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/thethiny', 'html_url': 'https://github.com/thethiny', 'followers_url': 'https://api.github.com/users/thethiny/followers', 'following_url': 'https://api.github.com/users/thethiny/following{/other_user}', 'gists_url': 'https://api.github.com/users/thethiny/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/thethiny/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/thethiny/subscriptions', 'organizations_url': 'https://api.github.com/users/thethiny/orgs', 'repos_url': 'https://api.github.com/users/thethiny/repos', 'events_url': 'https://api.github.com/users/thethiny/events{/privacy}', 'received_events_url': 'https://api.github.com/users/thethiny/received_events', 'type': 'User', 'user_view_type': 'public', 'site_admin': False}, 'repo': {'id': 1298654395, 'node_id': 'R_kgDOTWfkuw', 'name': 'dolphin', 'full_name': 'thethiny/dolphin', 'private': False, 'owner': {'login': 'thethiny', 'id': 6018214, 'node_id': 'MDQ6VXNlcjYwMTgyMTQ=', 'avatar_url': 'https://avatars.githubusercontent.com/u/6018214?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/thethiny', 'html_url': 'https://github.com/thethiny', 'followers_url': 'https://api.github.com/users/thethiny/followers', 'following_url': 'https://api.github.com/users/thethiny/following{/other_user}', 'gists_url': 'https://api.github.com/users/thethiny/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/thethiny/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/thethiny/subscriptions', 'organizations_url': 'https://api.github.com/users/thethiny/orgs', 'repos_url': 'https://api.github.com/users/thethiny/repos', 'events_url': 'https://api.github.com/users/thethiny/events{/privacy}', 'received_events_url': 'https://api.github.com/users/thethiny/received_events', 'type': 'User', 'user_view_type': 'public', 'site_admin': False}, 'html_url': 'https://github.com/thethiny/dolphin', 'description': 'Dolphin is a GameCube / Wii emulator, allowing you to play games for these two platforms on PC with improvements.', 'fork': True, 'url': 'https://api.github.com/repos/thethiny/dolphin', 'forks_url': 'https://api.github.com/repos/thethiny/dolphin/forks', 'keys_url': 'https://api.github.com/repos/thethiny/dolphin/keys{/key_id}', 'collaborators_url': 'https://api.github.com/repos/thethiny/dolphin/collaborators{/collaborator}', 'teams_url': 'https://api.github.com/repos/thethiny/dolphin/teams', 'hooks_url': 'https://api.github.com/repos/thethiny/dolphin/hooks', 'issue_events_url': 'https://api.github.com/repos/thethiny/dolphin/issues/events{/number}', 'events_url': 'https://api.github.com/repos/thethiny/dolphin/events', 'assignees_url': 'https://api.github.com/repos/thethiny/dolphin/assignees{/user}', 'branches_url': 'https://api.github.com/repos/thethiny/dolphin/branches{/branch}', 'tags_url': 'https://api.github.com/repos/thethiny/dolphin/tags', 'blobs_url': 'https://api.github.com/repos/thethiny/dolphin/git/blobs{/sha}', 'git_tags_url': 'https://api.github.com/repos/thethiny/dolphin/git/tags{/sha}', 'git_refs_url': 'https://api.github.com/repos/thethiny/dolphin/git/refs{/sha}', 'trees_url': 'https://api.github.com/repos/thethiny/dolphin/git/trees{/sha}', 'statuses_url': 'https://api.github.com/repos/thethiny/dolphin/statuses/{sha}', 'languages_url': 'https://api.github.com/repos/thethiny/dolphin/languages', 'stargazers_url': 'https://api.github.com/repos/thethiny/dolphin/stargazers', 'contributors_url': 'https://api.github.com/repos/thethiny/dolphin/contributors', 'subscribers_url': 'https://api.github.com/repos/thethiny/dolphin/subscribers', 'subscription_url': 'https://api.github.com/repos/thethiny/dolphin/subscription', 'commits_url': 'https://api.github.com/repos/thethiny/dolphin/commits{/sha}', 'git_commits_url': 'https://api.github.com/repos/thethiny/dolphin/git/commits{/sha}', 'comments_url': 'https://api.github.com/repos/thethiny/dolphin/comments{/number}', 'issue_comment_url': 'https://api.github.com/repos/thethiny/dolphin/issues/comments{/number}', 'contents_url': 'https://api.github.com/repos/thethiny/dolphin/contents/{+path}', 'compare_url': 'https://api.github.com/repos/thethiny/dolphin/compare/{base}...{head}', 'merges_url': 'https://api.github.com/repos/thethiny/dolphin/merges', 'archive_url': 'https://api.github.com/repos/thethiny/dolphin/{archive_format}{/ref}', 'downloads_url': 'https://api.github.com/repos/thethiny/dolphin/downloads', 'issues_url': 'https://api.github.com/repos/thethiny/dolphin/issues{/number}', 'pulls_url': 'https://api.github.com/repos/thethiny/dolphin/pulls{/number}', 'milestones_url': 'https://api.github.com/repos/thethiny/dolphin/milestones{/number}', 'notifications_url': 'https://api.github.com/repos/thethiny/dolphin/notifications{?since,all,participating}', 'labels_url': 'https://api.github.com/repos/thethiny/dolphin/labels{/name}', 'releases_url': 'https://api.github.com/repos/thethiny/dolphin/releases{/id}', 'deployments_url': 'https://api.github.com/repos/thethiny/dolphin/deployments', 'created_at': '2026-07-12T22:09:13Z', 'updated_at': '2026-07-12T22:09:13Z', 'pushed_at': '2026-07-18T20:35:03Z', 'git_url': 'git://github.com/thethiny/dolphin.git', 'ssh_url': 'git@github.com:thethiny/dolphin.git', 'clone_url': 'https://github.com/thethiny/dolphin.git', 'svn_url': 'https://github.com/thethiny/dolphin', 'homepage': 'https://dolphin-emu.org', 'size': 515471, 'stargazers_count': 0, 'watchers_count': 0, 'language': None, 'has_issues': False, 'has_projects': True, 'has_downloads': True, 'has_wiki': True, 'has_pages': False, 'has_discussions': False, 'forks_count': 0, 'mirror_url': None, 'archived': False, 'disabled': False, 'open_issues_count': 0, 'license': {'key': 'other', 'name': 'Other', 'spdx_id': 'NOASSERTION', 'url': None, 'node_id': 'MDc6TGljZW5zZTA='}, 'allow_forking': True, 'is_template': False, 'web_commit_signoff_required': False, 'has_pull_requests': True, 'pull_request_creation_policy': 'all', 'topics': [], 'visibility': 'public', 'forks': 0, 'open_issues': 0, 'watchers': 0, 'default_branch': 'master', 'allow_squash_merge': True, 'allow_merge_commit': True, 'allow_rebase_merge': True, 'allow_auto_merge': False, 'delete_branch_on_merge': False, 'allow_update_branch': False, 'use_squash_pr_title_as_default': False, 'squash_merge_commit_message': 'COMMIT_MESSAGES', 'squash_merge_commit_title': 'COMMIT_OR_PR_TITLE', 'merge_commit_message': 'PR_TITLE', 'merge_commit_title': 'MERGE_MESSAGE'}}, 'base': {'label': 'dolphin-emu:master', 'ref': 'master', 'sha': 'd3b2943807dd0073f7767947466dd73cccfef319', 'user': {'login': 'dolphin-emu', 'id': 5050316, 'node_id': 'MDEyOk9yZ2FuaXphdGlvbjUwNTAzMTY=', 'avatar_url': 'https://avatars.githubusercontent.com/u/5050316?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/dolphin-emu', 'html_url': 'https://github.com/dolphin-emu', 'followers_url': 'https://api.github.com/users/dolphin-emu/followers', 'following_url': 'https://api.github.com/users/dolphin-emu/following{/other_user}', 'gists_url': 'https://api.github.com/users/dolphin-emu/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/dolphin-emu/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/dolphin-emu/subscriptions', 'organizations_url': 'https://api.github.com/users/dolphin-emu/orgs', 'repos_url': 'https://api.github.com/users/dolphin-emu/repos', 'events_url': 'https://api.github.com/users/dolphin-emu/events{/privacy}', 'received_events_url': 'https://api.github.com/users/dolphin-emu/received_events', 'type': 'Organization', 'user_view_type': 'public', 'site_admin': False}, 'repo': {'id': 11577304, 'node_id': 'MDEwOlJlcG9zaXRvcnkxMTU3NzMwNA==', 'name': 'dolphin', 'full_name': 'dolphin-emu/dolphin', 'private': False, 'owner': {'login': 'dolphin-emu', 'id': 5050316, 'node_id': 'MDEyOk9yZ2FuaXphdGlvbjUwNTAzMTY=', 'avatar_url': 'https://avatars.githubusercontent.com/u/5050316?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/dolphin-emu', 'html_url': 'https://github.com/dolphin-emu', 'followers_url': 'https://api.github.com/users/dolphin-emu/followers', 'following_url': 'https://api.github.com/users/dolphin-emu/following{/other_user}', 'gists_url': 'https://api.github.com/users/dolphin-emu/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/dolphin-emu/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/dolphin-emu/subscriptions', 'organizations_url': 'https://api.github.com/users/dolphin-emu/orgs', 'repos_url': 'https://api.github.com/users/dolphin-emu/repos', 'events_url': 'https://api.github.com/users/dolphin-emu/events{/privacy}', 'received_events_url': 'https://api.github.com/users/dolphin-emu/received_events', 'type': 'Organization', 'user_view_type': 'public', 'site_admin': False}, 'html_url': 'https://github.com/dolphin-emu/dolphin', 'description': 'Dolphin is a GameCube / Wii emulator, allowing you to play games for these two platforms on PC with improvements.', 'fork': False, 'url': 'https://api.github.com/repos/dolphin-emu/dolphin', 'forks_url': 'https://api.github.com/repos/dolphin-emu/dolphin/forks', 'keys_url': 'https://api.github.com/repos/dolphin-emu/dolphin/keys{/key_id}', 'collaborators_url': 'https://api.github.com/repos/dolphin-emu/dolphin/collaborators{/collaborator}', 'teams_url': 'https://api.github.com/repos/dolphin-emu/dolphin/teams', 'hooks_url': 'https://api.github.com/repos/dolphin-emu/dolphin/hooks', 'issue_events_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/events{/number}', 'events_url': 'https://api.github.com/repos/dolphin-emu/dolphin/events', 'assignees_url': 'https://api.github.com/repos/dolphin-emu/dolphin/assignees{/user}', 'branches_url': 'https://api.github.com/repos/dolphin-emu/dolphin/branches{/branch}', 'tags_url': 'https://api.github.com/repos/dolphin-emu/dolphin/tags', 'blobs_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/blobs{/sha}', 'git_tags_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/tags{/sha}', 'git_refs_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/refs{/sha}', 'trees_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/trees{/sha}', 'statuses_url': 'https://api.github.com/repos/dolphin-emu/dolphin/statuses/{sha}', 'languages_url': 'https://api.github.com/repos/dolphin-emu/dolphin/languages', 'stargazers_url': 'https://api.github.com/repos/dolphin-emu/dolphin/stargazers', 'contributors_url': 'https://api.github.com/repos/dolphin-emu/dolphin/contributors', 'subscribers_url': 'https://api.github.com/repos/dolphin-emu/dolphin/subscribers', 'subscription_url': 'https://api.github.com/repos/dolphin-emu/dolphin/subscription', 'commits_url': 'https://api.github.com/repos/dolphin-emu/dolphin/commits{/sha}', 'git_commits_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/commits{/sha}', 'comments_url': 'https://api.github.com/repos/dolphin-emu/dolphin/comments{/number}', 'issue_comment_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/comments{/number}', 'contents_url': 'https://api.github.com/repos/dolphin-emu/dolphin/contents/{+path}', 'compare_url': 'https://api.github.com/repos/dolphin-emu/dolphin/compare/{base}...{head}', 'merges_url': 'https://api.github.com/repos/dolphin-emu/dolphin/merges', 'archive_url': 'https://api.github.com/repos/dolphin-emu/dolphin/{archive_format}{/ref}', 'downloads_url': 'https://api.github.com/repos/dolphin-emu/dolphin/downloads', 'issues_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues{/number}', 'pulls_url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls{/number}', 'milestones_url': 'https://api.github.com/repos/dolphin-emu/dolphin/milestones{/number}', 'notifications_url': 'https://api.github.com/repos/dolphin-emu/dolphin/notifications{?since,all,participating}', 'labels_url': 'https://api.github.com/repos/dolphin-emu/dolphin/labels{/name}', 'releases_url': 'https://api.github.com/repos/dolphin-emu/dolphin/releases{/id}', 'deployments_url': 'https://api.github.com/repos/dolphin-emu/dolphin/deployments', 'created_at': '2013-07-22T09:07:57Z', 'updated_at': '2026-07-18T23:13:54Z', 'pushed_at': '2026-07-18T10:34:54Z', 'git_url': 'git://github.com/dolphin-emu/dolphin.git', 'ssh_url': 'git@github.com:dolphin-emu/dolphin.git', 'clone_url': 'https://github.com/dolphin-emu/dolphin.git', 'svn_url': 'https://github.com/dolphin-emu/dolphin', 'homepage': 'https://dolphin-emu.org', 'size': 558448, 'stargazers_count': 15273, 'watchers_count': 15273, 'language': 'C++', 'has_issues': False, 'has_projects': False, 'has_downloads': True, 'has_wiki': True, 'has_pages': False, 'has_discussions': False, 'forks_count': 3162, 'mirror_url': None, 'archived': False, 'disabled': False, 'open_issues_count': 446, 'license': {'key': 'other', 'name': 'Other', 'spdx_id': 'NOASSERTION', 'url': None, 'node_id': 'MDc6TGljZW5zZTA='}, 'allow_forking': True, 'is_template': False, 'web_commit_signoff_required': False, 'has_pull_requests': True, 'pull_request_creation_policy': 'all', 'topics': ['cpp', 'emulation', 'emulator', 'gamecube', 'wii'], 'visibility': 'public', 'forks': 3162, 'open_issues': 446, 'watchers': 15273, 'default_branch': 'master', 'allow_squash_merge': False, 'allow_merge_commit': True, 'allow_rebase_merge': False, 'allow_auto_merge': False, 'delete_branch_on_merge': False, 'allow_update_branch': False, 'use_squash_pr_title_as_default': False, 'squash_merge_commit_message': 'COMMIT_MESSAGES', 'squash_merge_commit_title': 'COMMIT_OR_PR_TITLE', 'merge_commit_message': 'PR_TITLE', 'merge_commit_title': 'MERGE_MESSAGE'}}, '_links': {'self': {'href': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/14731'}, 'html': {'href': 'https://github.com/dolphin-emu/dolphin/pull/14731'}, 'issue': {'href': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/14731'}, 'comments': {'href': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/14731/comments'}, 'review_comments': {'href': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/14731/comments'}, 'review_comment': {'href': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/comments{/number}'}, 'commits': {'href': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/14731/commits'}, 'statuses': {'href': 'https://api.github.com/repos/dolphin-emu/dolphin/statuses/24b41d58df2315831b74f76b95417f2739d02f9d'}}, 'author_association': 'NONE', 'auto_merge': None, 'assignee': None, 'active_lock_reason': None}, 'repository': {'id': 11577304, 'node_id': 'MDEwOlJlcG9zaXRvcnkxMTU3NzMwNA==', 'name': 'dolphin', 'full_name': 'dolphin-emu/dolphin', 'private': False, 'owner': {'login': 'dolphin-emu', 'id': 5050316, 'node_id': 'MDEyOk9yZ2FuaXphdGlvbjUwNTAzMTY=', 'avatar_url': 'https://avatars.githubusercontent.com/u/5050316?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/dolphin-emu', 'html_url': 'https://github.com/dolphin-emu', 'followers_url': 'https://api.github.com/users/dolphin-emu/followers', 'following_url': 'https://api.github.com/users/dolphin-emu/following{/other_user}', 'gists_url': 'https://api.github.com/users/dolphin-emu/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/dolphin-emu/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/dolphin-emu/subscriptions', 'organizations_url': 'https://api.github.com/users/dolphin-emu/orgs', 'repos_url': 'https://api.github.com/users/dolphin-emu/repos', 'events_url': 'https://api.github.com/users/dolphin-emu/events{/privacy}', 'received_events_url': 'https://api.github.com/users/dolphin-emu/received_events', 'type': 'Organization', 'user_view_type': 'public', 'site_admin': False}, 'html_url': 'https://github.com/dolphin-emu/dolphin', 'description': 'Dolphin is a GameCube / Wii emulator, allowing you to play games for these two platforms on PC with improvements.', 'fork': False, 'url': 'https://api.github.com/repos/dolphin-emu/dolphin', 'forks_url': 'https://api.github.com/repos/dolphin-emu/dolphin/forks', 'keys_url': 'https://api.github.com/repos/dolphin-emu/dolphin/keys{/key_id}', 'collaborators_url': 'https://api.github.com/repos/dolphin-emu/dolphin/collaborators{/collaborator}', 'teams_url': 'https://api.github.com/repos/dolphin-emu/dolphin/teams', 'hooks_url': 'https://api.github.com/repos/dolphin-emu/dolphin/hooks', 'issue_events_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/events{/number}', 'events_url': 'https://api.github.com/repos/dolphin-emu/dolphin/events', 'assignees_url': 'https://api.github.com/repos/dolphin-emu/dolphin/assignees{/user}', 'branches_url': 'https://api.github.com/repos/dolphin-emu/dolphin/branches{/branch}', 'tags_url': 'https://api.github.com/repos/dolphin-emu/dolphin/tags', 'blobs_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/blobs{/sha}', 'git_tags_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/tags{/sha}', 'git_refs_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/refs{/sha}', 'trees_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/trees{/sha}', 'statuses_url': 'https://api.github.com/repos/dolphin-emu/dolphin/statuses/{sha}', 'languages_url': 'https://api.github.com/repos/dolphin-emu/dolphin/languages', 'stargazers_url': 'https://api.github.com/repos/dolphin-emu/dolphin/stargazers', 'contributors_url': 'https://api.github.com/repos/dolphin-emu/dolphin/contributors', 'subscribers_url': 'https://api.github.com/repos/dolphin-emu/dolphin/subscribers', 'subscription_url': 'https://api.github.com/repos/dolphin-emu/dolphin/subscription', 'commits_url': 'https://api.github.com/repos/dolphin-emu/dolphin/commits{/sha}', 'git_commits_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/commits{/sha}', 'comments_url': 'https://api.github.com/repos/dolphin-emu/dolphin/comments{/number}', 'issue_comment_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/comments{/number}', 'contents_url': 'https://api.github.com/repos/dolphin-emu/dolphin/contents/{+path}', 'compare_url': 'https://api.github.com/repos/dolphin-emu/dolphin/compare/{base}...{head}', 'merges_url': 'https://api.github.com/repos/dolphin-emu/dolphin/merges', 'archive_url': 'https://api.github.com/repos/dolphin-emu/dolphin/{archive_format}{/ref}', 'downloads_url': 'https://api.github.com/repos/dolphin-emu/dolphin/downloads', 'issues_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues{/number}', 'pulls_url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls{/number}', 'milestones_url': 'https://api.github.com/repos/dolphin-emu/dolphin/milestones{/number}', 'notifications_url': 'https://api.github.com/repos/dolphin-emu/dolphin/notifications{?since,all,participating}', 'labels_url': 'https://api.github.com/repos/dolphin-emu/dolphin/labels{/name}', 'releases_url': 'https://api.github.com/repos/dolphin-emu/dolphin/releases{/id}', 'deployments_url': 'https://api.github.com/repos/dolphin-emu/dolphin/deployments', 'created_at': '2013-07-22T09:07:57Z', 'updated_at': '2026-07-18T23:13:54Z', 'pushed_at': '2026-07-18T10:34:54Z', 'git_url': 'git://github.com/dolphin-emu/dolphin.git', 'ssh_url': 'git@github.com:dolphin-emu/dolphin.git', 'clone_url': 'https://github.com/dolphin-emu/dolphin.git', 'svn_url': 'https://github.com/dolphin-emu/dolphin', 'homepage': 'https://dolphin-emu.org', 'size': 558448, 'stargazers_count': 15273, 'watchers_count': 15273, 'language': 'C++', 'has_issues': False, 'has_projects': False, 'has_downloads': True, 'has_wiki': True, 'has_pages': False, 'has_discussions': False, 'forks_count': 3162, 'mirror_url': None, 'archived': False, 'disabled': False, 'open_issues_count': 446, 'license': {'key': 'other', 'name': 'Other', 'spdx_id': 'NOASSERTION', 'url': None, 'node_id': 'MDc6TGljZW5zZTA='}, 'allow_forking': True, 'is_template': False, 'web_commit_signoff_required': False, 'has_pull_requests': True, 'pull_request_creation_policy': 'all', 'topics': ['cpp', 'emulation', 'emulator', 'gamecube', 'wii'], 'visibility': 'public', 'forks': 3162, 'open_issues': 446, 'watchers': 15273, 'default_branch': 'master', 'custom_properties': {}}, 'organization': {'login': 'dolphin-emu', 'id': 5050316, 'node_id': 'MDEyOk9yZ2FuaXphdGlvbjUwNTAzMTY=', 'url': 'https://api.github.com/orgs/dolphin-emu', 'repos_url': 'https://api.github.com/orgs/dolphin-emu/repos', 'events_url': 'https://api.github.com/orgs/dolphin-emu/events', 'hooks_url': 'https://api.github.com/orgs/dolphin-emu/hooks', 'issues_url': 'https://api.github.com/orgs/dolphin-emu/issues', 'members_url': 'https://api.github.com/orgs/dolphin-emu/members{/member}', 'public_members_url': 'https://api.github.com/orgs/dolphin-emu/public_members{/member}', 'avatar_url': 'https://avatars.githubusercontent.com/u/5050316?v=4', 'description': ''}, 'sender': {'login': 'thethiny', 'id': 6018214, 'node_id': 'MDQ6VXNlcjYwMTgyMTQ=', 'avatar_url': 'https://avatars.githubusercontent.com/u/6018214?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/thethiny', 'html_url': 'https://github.com/thethiny', 'followers_url': 'https://api.github.com/users/thethiny/followers', 'following_url': 'https://api.github.com/users/thethiny/following{/other_user}', 'gists_url': 'https://api.github.com/users/thethiny/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/thethiny/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/thethiny/subscriptions', 'organizations_url': 'https://api.github.com/users/thethiny/orgs', 'repos_url': 'https://api.github.com/users/thethiny/repos', 'events_url': 'https://api.github.com/users/thethiny/events{/privacy}', 'received_events_url': 'https://api.github.com/users/thethiny/received_events', 'type': 'User', 'user_view_type': 'public', 'site_admin': False}, 'installation': {'id': 35437981, 'node_id': 'MDIzOkludGVncmF0aW9uSW5zdGFsbGF0aW9uMzU0Mzc5ODE='}}, 'type': 'raw_gh_hook'}
2026-07-18T23:36:12.676082	{'source': 'webserver', 'gh_type': 'pull_request_review', 'raw': {'action': 'submitted', 'review': {'id': 4729499717, 'node_id': 'PRR_kwDOALCn2M8AAAABGeZwRQ', 'user': {'login': 'thethiny', 'id': 6018214, 'node_id': 'MDQ6VXNlcjYwMTgyMTQ=', 'avatar_url': 'https://avatars.githubusercontent.com/u/6018214?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/thethiny', 'html_url': 'https://github.com/thethiny', 'followers_url': 'https://api.github.com/users/thethiny/followers', 'following_url': 'https://api.github.com/users/thethiny/following{/other_user}', 'gists_url': 'https://api.github.com/users/thethiny/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/thethiny/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/thethiny/subscriptions', 'organizations_url': 'https://api.github.com/users/thethiny/orgs', 'repos_url': 'https://api.github.com/users/thethiny/repos', 'events_url': 'https://api.github.com/users/thethiny/events{/privacy}', 'received_events_url': 'https://api.github.com/users/thethiny/received_events', 'type': 'User', 'user_view_type': 'public', 'site_admin': False}, 'body': None, 'commit_id': '24b41d58df2315831b74f76b95417f2739d02f9d', 'state': 'commented', 'html_url': 'https://github.com/dolphin-emu/dolphin/pull/14731#pullrequestreview-4729499717', 'pull_request_url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/14731', '_links': {'html': {'href': 'https://github.com/dolphin-emu/dolphin/pull/14731#pullrequestreview-4729499717'}, 'pull_request': {'href': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/14731'}}, 'submitted_at': '2026-07-18T23:36:11Z', 'updated_at': '2026-07-18T23:36:11Z', 'author_association': 'NONE'}, 'pull_request': {'url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/14731', 'id': 4056977334, 'node_id': 'PR_kwDOALCn2M7x0I-2', 'html_url': 'https://github.com/dolphin-emu/dolphin/pull/14731', 'diff_url': 'https://github.com/dolphin-emu/dolphin/pull/14731.diff', 'patch_url': 'https://github.com/dolphin-emu/dolphin/pull/14731.patch', 'issue_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/14731', 'number': 14731, 'state': 'open', 'locked': False, 'title': 'Convert To WBFS Support', 'user': {'login': 'thethiny', 'id': 6018214, 'node_id': 'MDQ6VXNlcjYwMTgyMTQ=', 'avatar_url': 'https://avatars.githubusercontent.com/u/6018214?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/thethiny', 'html_url': 'https://github.com/thethiny', 'followers_url': 'https://api.github.com/users/thethiny/followers', 'following_url': 'https://api.github.com/users/thethiny/following{/other_user}', 'gists_url': 'https://api.github.com/users/thethiny/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/thethiny/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/thethiny/subscriptions', 'organizations_url': 'https://api.github.com/users/thethiny/orgs', 'repos_url': 'https://api.github.com/users/thethiny/repos', 'events_url': 'https://api.github.com/users/thethiny/events{/privacy}', 'received_events_url': 'https://api.github.com/users/thethiny/received_events', 'type': 'User', 'user_view_type': 'public', 'site_admin': False}, 'body': "This PR introduces Conversion **to** WBFS support. WBFS is the format that is used by USB Loaders on a real Wii device.\r\n\r\n## Design decisions & hardcoded values\r\nThe writer uses fixed sector sizes that match what [libwbfs (the reference implementation by kwiirk)](https://github.com/kwiirk/wbfs/blob/master/libwbfs/libwbfs.c#L128-L134) computes for a standard single-layer Wii disc. These 2 hardcodes are stable and work correctly across all my testings.\r\n- HD sector shift: 9 (512 bytes)\r\n- WBFS sector shift: 21 (2 MiB)\r\nThese are not configurable via the UI. All existing WBFS tools use these values, and since the aim is to support USB Loaders then this has been tested and it is working on a real Wii.\r\n\r\nConverting from WBFS is not enabled. The existing `WbfsFileReader` reports `DataSizeType::UpperBound`, and `ShouldAllowConversion()` requires `Accurate`. I am able to support this but since it was hardcoded by the Dolphin team I thought a discussion is warranted.\r\n\r\n## Testing\r\n- Verified with DolphinTool header and DolphinTool verify\r\n- Verified with wit FILETYPE and wit DUMP (Wiimm's ISO Tools recognizes valid WBFS structure, partitions, encryption)\r\n- Tested ISO to WBFS and RVZ to WBFS conversions\r\n- Output file sizes match Wii Backup Manager when scrubbing is enabled (~0.1% difference), works when scrubbing is disabled.\r\n- Output WBFS files play correctly in Dolphin\r\n- Output WBFS files play correctly on a real Wii using USB Loader GX e25c4f3\r\n", 'created_at': '2026-07-15T01:16:25Z', 'updated_at': '2026-07-18T23:33:13Z', 'closed_at': None, 'merged_at': None, 'merge_commit_sha': '228f93416dd80eb09da834ad7852c8eaa4d9212b', 'assignees': [], 'requested_reviewers': [], 'requested_teams': [], 'labels': [], 'milestone': None, 'draft': False, 'commits_url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/14731/commits', 'review_comments_url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/14731/comments', 'review_comment_url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/comments{/number}', 'comments_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/14731/comments', 'statuses_url': 'https://api.github.com/repos/dolphin-emu/dolphin/statuses/24b41d58df2315831b74f76b95417f2739d02f9d', 'head': {'label': 'thethiny:wbfs-conversion', 'ref': 'wbfs-conversion', 'sha': '24b41d58df2315831b74f76b95417f2739d02f9d', 'user': {'login': 'thethiny', 'id': 6018214, 'node_id': 'MDQ6VXNlcjYwMTgyMTQ=', 'avatar_url': 'https://avatars.githubusercontent.com/u/6018214?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/thethiny', 'html_url': 'https://github.com/thethiny', 'followers_url': 'https://api.github.com/users/thethiny/followers', 'following_url': 'https://api.github.com/users/thethiny/following{/other_user}', 'gists_url': 'https://api.github.com/users/thethiny/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/thethiny/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/thethiny/subscriptions', 'organizations_url': 'https://api.github.com/users/thethiny/orgs', 'repos_url': 'https://api.github.com/users/thethiny/repos', 'events_url': 'https://api.github.com/users/thethiny/events{/privacy}', 'received_events_url': 'https://api.github.com/users/thethiny/received_events', 'type': 'User', 'user_view_type': 'public', 'site_admin': False}, 'repo': {'id': 1298654395, 'node_id': 'R_kgDOTWfkuw', 'name': 'dolphin', 'full_name': 'thethiny/dolphin', 'private': False, 'owner': {'login': 'thethiny', 'id': 6018214, 'node_id': 'MDQ6VXNlcjYwMTgyMTQ=', 'avatar_url': 'https://avatars.githubusercontent.com/u/6018214?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/thethiny', 'html_url': 'https://github.com/thethiny', 'followers_url': 'https://api.github.com/users/thethiny/followers', 'following_url': 'https://api.github.com/users/thethiny/following{/other_user}', 'gists_url': 'https://api.github.com/users/thethiny/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/thethiny/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/thethiny/subscriptions', 'organizations_url': 'https://api.github.com/users/thethiny/orgs', 'repos_url': 'https://api.github.com/users/thethiny/repos', 'events_url': 'https://api.github.com/users/thethiny/events{/privacy}', 'received_events_url': 'https://api.github.com/users/thethiny/received_events', 'type': 'User', 'user_view_type': 'public', 'site_admin': False}, 'html_url': 'https://github.com/thethiny/dolphin', 'description': 'Dolphin is a GameCube / Wii emulator, allowing you to play games for these two platforms on PC with improvements.', 'fork': True, 'url': 'https://api.github.com/repos/thethiny/dolphin', 'forks_url': 'https://api.github.com/repos/thethiny/dolphin/forks', 'keys_url': 'https://api.github.com/repos/thethiny/dolphin/keys{/key_id}', 'collaborators_url': 'https://api.github.com/repos/thethiny/dolphin/collaborators{/collaborator}', 'teams_url': 'https://api.github.com/repos/thethiny/dolphin/teams', 'hooks_url': 'https://api.github.com/repos/thethiny/dolphin/hooks', 'issue_events_url': 'https://api.github.com/repos/thethiny/dolphin/issues/events{/number}', 'events_url': 'https://api.github.com/repos/thethiny/dolphin/events', 'assignees_url': 'https://api.github.com/repos/thethiny/dolphin/assignees{/user}', 'branches_url': 'https://api.github.com/repos/thethiny/dolphin/branches{/branch}', 'tags_url': 'https://api.github.com/repos/thethiny/dolphin/tags', 'blobs_url': 'https://api.github.com/repos/thethiny/dolphin/git/blobs{/sha}', 'git_tags_url': 'https://api.github.com/repos/thethiny/dolphin/git/tags{/sha}', 'git_refs_url': 'https://api.github.com/repos/thethiny/dolphin/git/refs{/sha}', 'trees_url': 'https://api.github.com/repos/thethiny/dolphin/git/trees{/sha}', 'statuses_url': 'https://api.github.com/repos/thethiny/dolphin/statuses/{sha}', 'languages_url': 'https://api.github.com/repos/thethiny/dolphin/languages', 'stargazers_url': 'https://api.github.com/repos/thethiny/dolphin/stargazers', 'contributors_url': 'https://api.github.com/repos/thethiny/dolphin/contributors', 'subscribers_url': 'https://api.github.com/repos/thethiny/dolphin/subscribers', 'subscription_url': 'https://api.github.com/repos/thethiny/dolphin/subscription', 'commits_url': 'https://api.github.com/repos/thethiny/dolphin/commits{/sha}', 'git_commits_url': 'https://api.github.com/repos/thethiny/dolphin/git/commits{/sha}', 'comments_url': 'https://api.github.com/repos/thethiny/dolphin/comments{/number}', 'issue_comment_url': 'https://api.github.com/repos/thethiny/dolphin/issues/comments{/number}', 'contents_url': 'https://api.github.com/repos/thethiny/dolphin/contents/{+path}', 'compare_url': 'https://api.github.com/repos/thethiny/dolphin/compare/{base}...{head}', 'merges_url': 'https://api.github.com/repos/thethiny/dolphin/merges', 'archive_url': 'https://api.github.com/repos/thethiny/dolphin/{archive_format}{/ref}', 'downloads_url': 'https://api.github.com/repos/thethiny/dolphin/downloads', 'issues_url': 'https://api.github.com/repos/thethiny/dolphin/issues{/number}', 'pulls_url': 'https://api.github.com/repos/thethiny/dolphin/pulls{/number}', 'milestones_url': 'https://api.github.com/repos/thethiny/dolphin/milestones{/number}', 'notifications_url': 'https://api.github.com/repos/thethiny/dolphin/notifications{?since,all,participating}', 'labels_url': 'https://api.github.com/repos/thethiny/dolphin/labels{/name}', 'releases_url': 'https://api.github.com/repos/thethiny/dolphin/releases{/id}', 'deployments_url': 'https://api.github.com/repos/thethiny/dolphin/deployments', 'created_at': '2026-07-12T22:09:13Z', 'updated_at': '2026-07-12T22:09:13Z', 'pushed_at': '2026-07-18T20:35:03Z', 'git_url': 'git://github.com/thethiny/dolphin.git', 'ssh_url': 'git@github.com:thethiny/dolphin.git', 'clone_url': 'https://github.com/thethiny/dolphin.git', 'svn_url': 'https://github.com/thethiny/dolphin', 'homepage': 'https://dolphin-emu.org', 'size': 515471, 'stargazers_count': 0, 'watchers_count': 0, 'language': None, 'has_issues': False, 'has_projects': True, 'has_downloads': True, 'has_wiki': True, 'has_pages': False, 'has_discussions': False, 'forks_count': 0, 'mirror_url': None, 'archived': False, 'disabled': False, 'open_issues_count': 0, 'license': {'key': 'other', 'name': 'Other', 'spdx_id': 'NOASSERTION', 'url': None, 'node_id': 'MDc6TGljZW5zZTA='}, 'allow_forking': True, 'is_template': False, 'web_commit_signoff_required': False, 'has_pull_requests': True, 'pull_request_creation_policy': 'all', 'topics': [], 'visibility': 'public', 'forks': 0, 'open_issues': 0, 'watchers': 0, 'default_branch': 'master', 'allow_squash_merge': True, 'allow_merge_commit': True, 'allow_rebase_merge': True, 'allow_auto_merge': False, 'delete_branch_on_merge': False, 'allow_update_branch': False, 'use_squash_pr_title_as_default': False, 'squash_merge_commit_message': 'COMMIT_MESSAGES', 'squash_merge_commit_title': 'COMMIT_OR_PR_TITLE', 'merge_commit_message': 'PR_TITLE', 'merge_commit_title': 'MERGE_MESSAGE'}}, 'base': {'label': 'dolphin-emu:master', 'ref': 'master', 'sha': 'd3b2943807dd0073f7767947466dd73cccfef319', 'user': {'login': 'dolphin-emu', 'id': 5050316, 'node_id': 'MDEyOk9yZ2FuaXphdGlvbjUwNTAzMTY=', 'avatar_url': 'https://avatars.githubusercontent.com/u/5050316?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/dolphin-emu', 'html_url': 'https://github.com/dolphin-emu', 'followers_url': 'https://api.github.com/users/dolphin-emu/followers', 'following_url': 'https://api.github.com/users/dolphin-emu/following{/other_user}', 'gists_url': 'https://api.github.com/users/dolphin-emu/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/dolphin-emu/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/dolphin-emu/subscriptions', 'organizations_url': 'https://api.github.com/users/dolphin-emu/orgs', 'repos_url': 'https://api.github.com/users/dolphin-emu/repos', 'events_url': 'https://api.github.com/users/dolphin-emu/events{/privacy}', 'received_events_url': 'https://api.github.com/users/dolphin-emu/received_events', 'type': 'Organization', 'user_view_type': 'public', 'site_admin': False}, 'repo': {'id': 11577304, 'node_id': 'MDEwOlJlcG9zaXRvcnkxMTU3NzMwNA==', 'name': 'dolphin', 'full_name': 'dolphin-emu/dolphin', 'private': False, 'owner': {'login': 'dolphin-emu', 'id': 5050316, 'node_id': 'MDEyOk9yZ2FuaXphdGlvbjUwNTAzMTY=', 'avatar_url': 'https://avatars.githubusercontent.com/u/5050316?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/dolphin-emu', 'html_url': 'https://github.com/dolphin-emu', 'followers_url': 'https://api.github.com/users/dolphin-emu/followers', 'following_url': 'https://api.github.com/users/dolphin-emu/following{/other_user}', 'gists_url': 'https://api.github.com/users/dolphin-emu/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/dolphin-emu/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/dolphin-emu/subscriptions', 'organizations_url': 'https://api.github.com/users/dolphin-emu/orgs', 'repos_url': 'https://api.github.com/users/dolphin-emu/repos', 'events_url': 'https://api.github.com/users/dolphin-emu/events{/privacy}', 'received_events_url': 'https://api.github.com/users/dolphin-emu/received_events', 'type': 'Organization', 'user_view_type': 'public', 'site_admin': False}, 'html_url': 'https://github.com/dolphin-emu/dolphin', 'description': 'Dolphin is a GameCube / Wii emulator, allowing you to play games for these two platforms on PC with improvements.', 'fork': False, 'url': 'https://api.github.com/repos/dolphin-emu/dolphin', 'forks_url': 'https://api.github.com/repos/dolphin-emu/dolphin/forks', 'keys_url': 'https://api.github.com/repos/dolphin-emu/dolphin/keys{/key_id}', 'collaborators_url': 'https://api.github.com/repos/dolphin-emu/dolphin/collaborators{/collaborator}', 'teams_url': 'https://api.github.com/repos/dolphin-emu/dolphin/teams', 'hooks_url': 'https://api.github.com/repos/dolphin-emu/dolphin/hooks', 'issue_events_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/events{/number}', 'events_url': 'https://api.github.com/repos/dolphin-emu/dolphin/events', 'assignees_url': 'https://api.github.com/repos/dolphin-emu/dolphin/assignees{/user}', 'branches_url': 'https://api.github.com/repos/dolphin-emu/dolphin/branches{/branch}', 'tags_url': 'https://api.github.com/repos/dolphin-emu/dolphin/tags', 'blobs_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/blobs{/sha}', 'git_tags_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/tags{/sha}', 'git_refs_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/refs{/sha}', 'trees_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/trees{/sha}', 'statuses_url': 'https://api.github.com/repos/dolphin-emu/dolphin/statuses/{sha}', 'languages_url': 'https://api.github.com/repos/dolphin-emu/dolphin/languages', 'stargazers_url': 'https://api.github.com/repos/dolphin-emu/dolphin/stargazers', 'contributors_url': 'https://api.github.com/repos/dolphin-emu/dolphin/contributors', 'subscribers_url': 'https://api.github.com/repos/dolphin-emu/dolphin/subscribers', 'subscription_url': 'https://api.github.com/repos/dolphin-emu/dolphin/subscription', 'commits_url': 'https://api.github.com/repos/dolphin-emu/dolphin/commits{/sha}', 'git_commits_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/commits{/sha}', 'comments_url': 'https://api.github.com/repos/dolphin-emu/dolphin/comments{/number}', 'issue_comment_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/comments{/number}', 'contents_url': 'https://api.github.com/repos/dolphin-emu/dolphin/contents/{+path}', 'compare_url': 'https://api.github.com/repos/dolphin-emu/dolphin/compare/{base}...{head}', 'merges_url': 'https://api.github.com/repos/dolphin-emu/dolphin/merges', 'archive_url': 'https://api.github.com/repos/dolphin-emu/dolphin/{archive_format}{/ref}', 'downloads_url': 'https://api.github.com/repos/dolphin-emu/dolphin/downloads', 'issues_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues{/number}', 'pulls_url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls{/number}', 'milestones_url': 'https://api.github.com/repos/dolphin-emu/dolphin/milestones{/number}', 'notifications_url': 'https://api.github.com/repos/dolphin-emu/dolphin/notifications{?since,all,participating}', 'labels_url': 'https://api.github.com/repos/dolphin-emu/dolphin/labels{/name}', 'releases_url': 'https://api.github.com/repos/dolphin-emu/dolphin/releases{/id}', 'deployments_url': 'https://api.github.com/repos/dolphin-emu/dolphin/deployments', 'created_at': '2013-07-22T09:07:57Z', 'updated_at': '2026-07-18T23:13:54Z', 'pushed_at': '2026-07-18T10:34:54Z', 'git_url': 'git://github.com/dolphin-emu/dolphin.git', 'ssh_url': 'git@github.com:dolphin-emu/dolphin.git', 'clone_url': 'https://github.com/dolphin-emu/dolphin.git', 'svn_url': 'https://github.com/dolphin-emu/dolphin', 'homepage': 'https://dolphin-emu.org', 'size': 558448, 'stargazers_count': 15273, 'watchers_count': 15273, 'language': 'C++', 'has_issues': False, 'has_projects': False, 'has_downloads': True, 'has_wiki': True, 'has_pages': False, 'has_discussions': False, 'forks_count': 3162, 'mirror_url': None, 'archived': False, 'disabled': False, 'open_issues_count': 446, 'license': {'key': 'other', 'name': 'Other', 'spdx_id': 'NOASSERTION', 'url': None, 'node_id': 'MDc6TGljZW5zZTA='}, 'allow_forking': True, 'is_template': False, 'web_commit_signoff_required': False, 'has_pull_requests': True, 'pull_request_creation_policy': 'all', 'topics': ['cpp', 'emulation', 'emulator', 'gamecube', 'wii'], 'visibility': 'public', 'forks': 3162, 'open_issues': 446, 'watchers': 15273, 'default_branch': 'master', 'allow_squash_merge': False, 'allow_merge_commit': True, 'allow_rebase_merge': False, 'allow_auto_merge': False, 'delete_branch_on_merge': False, 'allow_update_branch': False, 'use_squash_pr_title_as_default': False, 'squash_merge_commit_message': 'COMMIT_MESSAGES', 'squash_merge_commit_title': 'COMMIT_OR_PR_TITLE', 'merge_commit_message': 'PR_TITLE', 'merge_commit_title': 'MERGE_MESSAGE'}}, '_links': {'self': {'href': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/14731'}, 'html': {'href': 'https://github.com/dolphin-emu/dolphin/pull/14731'}, 'issue': {'href': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/14731'}, 'comments': {'href': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/14731/comments'}, 'review_comments': {'href': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/14731/comments'}, 'review_comment': {'href': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/comments{/number}'}, 'commits': {'href': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/14731/commits'}, 'statuses': {'href': 'https://api.github.com/repos/dolphin-emu/dolphin/statuses/24b41d58df2315831b74f76b95417f2739d02f9d'}}, 'author_association': 'NONE', 'auto_merge': None, 'assignee': None, 'active_lock_reason': None}, 'repository': {'id': 11577304, 'node_id': 'MDEwOlJlcG9zaXRvcnkxMTU3NzMwNA==', 'name': 'dolphin', 'full_name': 'dolphin-emu/dolphin', 'private': False, 'owner': {'login': 'dolphin-emu', 'id': 5050316, 'node_id': 'MDEyOk9yZ2FuaXphdGlvbjUwNTAzMTY=', 'avatar_url': 'https://avatars.githubusercontent.com/u/5050316?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/dolphin-emu', 'html_url': 'https://github.com/dolphin-emu', 'followers_url': 'https://api.github.com/users/dolphin-emu/followers', 'following_url': 'https://api.github.com/users/dolphin-emu/following{/other_user}', 'gists_url': 'https://api.github.com/users/dolphin-emu/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/dolphin-emu/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/dolphin-emu/subscriptions', 'organizations_url': 'https://api.github.com/users/dolphin-emu/orgs', 'repos_url': 'https://api.github.com/users/dolphin-emu/repos', 'events_url': 'https://api.github.com/users/dolphin-emu/events{/privacy}', 'received_events_url': 'https://api.github.com/users/dolphin-emu/received_events', 'type': 'Organization', 'user_view_type': 'public', 'site_admin': False}, 'html_url': 'https://github.com/dolphin-emu/dolphin', 'description': 'Dolphin is a GameCube / Wii emulator, allowing you to play games for these two platforms on PC with improvements.', 'fork': False, 'url': 'https://api.github.com/repos/dolphin-emu/dolphin', 'forks_url': 'https://api.github.com/repos/dolphin-emu/dolphin/forks', 'keys_url': 'https://api.github.com/repos/dolphin-emu/dolphin/keys{/key_id}', 'collaborators_url': 'https://api.github.com/repos/dolphin-emu/dolphin/collaborators{/collaborator}', 'teams_url': 'https://api.github.com/repos/dolphin-emu/dolphin/teams', 'hooks_url': 'https://api.github.com/repos/dolphin-emu/dolphin/hooks', 'issue_events_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/events{/number}', 'events_url': 'https://api.github.com/repos/dolphin-emu/dolphin/events', 'assignees_url': 'https://api.github.com/repos/dolphin-emu/dolphin/assignees{/user}', 'branches_url': 'https://api.github.com/repos/dolphin-emu/dolphin/branches{/branch}', 'tags_url': 'https://api.github.com/repos/dolphin-emu/dolphin/tags', 'blobs_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/blobs{/sha}', 'git_tags_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/tags{/sha}', 'git_refs_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/refs{/sha}', 'trees_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/trees{/sha}', 'statuses_url': 'https://api.github.com/repos/dolphin-emu/dolphin/statuses/{sha}', 'languages_url': 'https://api.github.com/repos/dolphin-emu/dolphin/languages', 'stargazers_url': 'https://api.github.com/repos/dolphin-emu/dolphin/stargazers', 'contributors_url': 'https://api.github.com/repos/dolphin-emu/dolphin/contributors', 'subscribers_url': 'https://api.github.com/repos/dolphin-emu/dolphin/subscribers', 'subscription_url': 'https://api.github.com/repos/dolphin-emu/dolphin/subscription', 'commits_url': 'https://api.github.com/repos/dolphin-emu/dolphin/commits{/sha}', 'git_commits_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/commits{/sha}', 'comments_url': 'https://api.github.com/repos/dolphin-emu/dolphin/comments{/number}', 'issue_comment_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/comments{/number}', 'contents_url': 'https://api.github.com/repos/dolphin-emu/dolphin/contents/{+path}', 'compare_url': 'https://api.github.com/repos/dolphin-emu/dolphin/compare/{base}...{head}', 'merges_url': 'https://api.github.com/repos/dolphin-emu/dolphin/merges', 'archive_url': 'https://api.github.com/repos/dolphin-emu/dolphin/{archive_format}{/ref}', 'downloads_url': 'https://api.github.com/repos/dolphin-emu/dolphin/downloads', 'issues_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues{/number}', 'pulls_url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls{/number}', 'milestones_url': 'https://api.github.com/repos/dolphin-emu/dolphin/milestones{/number}', 'notifications_url': 'https://api.github.com/repos/dolphin-emu/dolphin/notifications{?since,all,participating}', 'labels_url': 'https://api.github.com/repos/dolphin-emu/dolphin/labels{/name}', 'releases_url': 'https://api.github.com/repos/dolphin-emu/dolphin/releases{/id}', 'deployments_url': 'https://api.github.com/repos/dolphin-emu/dolphin/deployments', 'created_at': '2013-07-22T09:07:57Z', 'updated_at': '2026-07-18T23:13:54Z', 'pushed_at': '2026-07-18T10:34:54Z', 'git_url': 'git://github.com/dolphin-emu/dolphin.git', 'ssh_url': 'git@github.com:dolphin-emu/dolphin.git', 'clone_url': 'https://github.com/dolphin-emu/dolphin.git', 'svn_url': 'https://github.com/dolphin-emu/dolphin', 'homepage': 'https://dolphin-emu.org', 'size': 558448, 'stargazers_count': 15273, 'watchers_count': 15273, 'language': 'C++', 'has_issues': False, 'has_projects': False, 'has_downloads': True, 'has_wiki': True, 'has_pages': False, 'has_discussions': False, 'forks_count': 3162, 'mirror_url': None, 'archived': False, 'disabled': False, 'open_issues_count': 446, 'license': {'key': 'other', 'name': 'Other', 'spdx_id': 'NOASSERTION', 'url': None, 'node_id': 'MDc6TGljZW5zZTA='}, 'allow_forking': True, 'is_template': False, 'web_commit_signoff_required': False, 'has_pull_requests': True, 'pull_request_creation_policy': 'all', 'topics': ['cpp', 'emulation', 'emulator', 'gamecube', 'wii'], 'visibility': 'public', 'forks': 3162, 'open_issues': 446, 'watchers': 15273, 'default_branch': 'master', 'custom_properties': {}}, 'organization': {'login': 'dolphin-emu', 'id': 5050316, 'node_id': 'MDEyOk9yZ2FuaXphdGlvbjUwNTAzMTY=', 'url': 'https://api.github.com/orgs/dolphin-emu', 'repos_url': 'https://api.github.com/orgs/dolphin-emu/repos', 'events_url': 'https://api.github.com/orgs/dolphin-emu/events', 'hooks_url': 'https://api.github.com/orgs/dolphin-emu/hooks', 'issues_url': 'https://api.github.com/orgs/dolphin-emu/issues', 'members_url': 'https://api.github.com/orgs/dolphin-emu/members{/member}', 'public_members_url': 'https://api.github.com/orgs/dolphin-emu/public_members{/member}', 'avatar_url': 'https://avatars.githubusercontent.com/u/5050316?v=4', 'description': ''}, 'sender': {'login': 'thethiny', 'id': 6018214, 'node_id': 'MDQ6VXNlcjYwMTgyMTQ=', 'avatar_url': 'https://avatars.githubusercontent.com/u/6018214?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/thethiny', 'html_url': 'https://github.com/thethiny', 'followers_url': 'https://api.github.com/users/thethiny/followers', 'following_url': 'https://api.github.com/users/thethiny/following{/other_user}', 'gists_url': 'https://api.github.com/users/thethiny/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/thethiny/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/thethiny/subscriptions', 'organizations_url': 'https://api.github.com/users/thethiny/orgs', 'repos_url': 'https://api.github.com/users/thethiny/repos', 'events_url': 'https://api.github.com/users/thethiny/events{/privacy}', 'received_events_url': 'https://api.github.com/users/thethiny/received_events', 'type': 'User', 'user_view_type': 'public', 'site_admin': False}, 'installation': {'id': 35437981, 'node_id': 'MDIzOkludGVncmF0aW9uSW5zdGFsbGF0aW9uMzU0Mzc5ODE='}}, 'type': 'raw_gh_hook'}
2026-07-18T23:33:15.219856	{'source': 'webserver', 'gh_type': 'pull_request_review_comment', 'raw': {'action': 'created', 'comment': {'url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/comments/3609413351', 'pull_request_review_id': 4729496492, 'id': 3609413351, 'node_id': 'PRRC_kwDOALCn2M7XI0bn', 'diff_hunk': '@@ -186,7 +380,304 @@ std::unique_ptr<WbfsFileReader> WbfsFileReader::Create(File::DirectIOFile file,\n   if (!reader->IsGood())\n     reader.reset();\n \n+  if (reader && reader->m_has_nkit_header)\n+    reader->ReadPartitionInfo();\n+\n   return reader;\n }\n \n+// Converts any disc image to WBFS with an NKit v2 header for lossless round-trips.\n+// Strips disc-level junk and partition-level junk (encrypted sectors whose decrypted\n+// content is zero or LFG padding), records a junk bitmap for reconstruction.\n+// See: https://github.com/dolphin-emu/dolphin/pull/14731\n+bool ConvertToWBFS(BlobReader* infile, const std::string& infile_path,\n+                   const std::string& outfile_path, const CompressCB& callback)\n+{\n+  ASSERT(infile->GetDataSizeType() == DataSizeType::Accurate ||\n+         infile->GetDataSizeType() == DataSizeType::UpperBound);\n+\n+  File::DirectIOFile outfile(outfile_path, File::AccessMode::Write);\n+  if (!outfile.IsOpen())\n+  {\n+    PanicAlertFmtT(\n+        "Failed to open the output file \\"{0}\\".\\n"\n+        "Check that you have permissions to write the target folder and that the media can "\n+        "be written.",\n+        outfile_path);\n+    return false;\n+  }\n+\n+  const u64 disc_size = infile->GetDataSize();\n+\n+  // These match the values used by standard WBFS tools (wwt, WBFS Manager)\n+  static constexpr u8 hd_sector_shift = 9;\n+  static constexpr u8 wbfs_sector_shift = 21;\n+  static constexpr u64 hd_sector_size = 1ull << hd_sector_shift;\n+  static constexpr u64 wbfs_sector_size = 1ull << wbfs_sector_shift;\n+\n+  const u64 blocks_per_disc = (disc_size + wbfs_sector_size - 1) / wbfs_sector_size;\n+  const u64 disc_info_size =\n+      Common::AlignUp(WII_DISC_HEADER_SIZE + blocks_per_disc * sizeof(u16), hd_sector_size);\n+\n+  // Read disc header (first 256 bytes contain disc_id, disc_num, title, etc.)\n+  std::vector<u8> disc_header(WII_DISC_HEADER_SIZE, 0);\n+  if (!infile->Read(0, WII_DISC_HEADER_SIZE, disc_header.data()))\n+  {\n+    PanicAlertFmtT("Failed to read from the input file \\"{0}\\".", infile_path);\n+    return false;\n+  }\n+\n+  // Use Volume for partition info and decrypted reads\n+  struct PartitionInfo\n+  {\n+    u64 data_offset;\n+    u64 data_size;\n+    Partition partition;\n+  };\n+  std::vector<PartitionInfo> partitions;\n+\n+  std::unique_ptr<VolumeDisc> volume = CreateDisc(infile_path);\n+  if (volume)\n+  {\n+    for (const Partition& partition : volume->GetPartitions())\n+    {\n+      const std::optional<u64> data_offset =\n+          volume->ReadSwappedAndShifted(partition.offset + 0x2B8, PARTITION_NONE);\n+      const std::optional<u64> data_size =\n+          volume->ReadSwappedAndShifted(partition.offset + 0x2BC, PARTITION_NONE);\n+      if (!data_offset || !data_size)\n+        continue;\n+\n+      PartitionInfo info;\n+      info.data_offset = partition.offset + *data_offset;\n+      info.data_size = *data_size;\n+      info.partition = partition;\n+      partitions.push_back(info);\n+    }\n+  }\n+\n+  // NKit v2 gap type bitmap: 1 bit per block, MSB-first, always sized for dual-layer\n+  const u64 gap_type_blocks = (DL_DVD_SIZE + wbfs_sector_size - 1) / wbfs_sector_size;\n+  const u64 gap_type_bytes = (gap_type_blocks + 7) / 8;\n+  std::vector<u8> gap_type(gap_type_bytes, 0);\n+\n+  // Compute data_start up front so we can write sectors during the scan\n+  const u64 data_start = Common::AlignUp(hd_sector_size + disc_info_size, wbfs_sector_size);\n+  const u16 wlba_base = static_cast<u16>(data_start / wbfs_sector_size);\n+\n+  // Single pass: scan, classify, hash, and write used sectors in one loop\n+  std::vector<u8> sector_buf(wbfs_sector_size, 0);\n+  std::vector<u16> wlba_table(blocks_per_disc, 0);\n+  u16 used_count = 0;\n+\n+  // NKit v2 stores four hash digests for verification\n+  auto sha1_ctx = Common::SHA1::CreateContext();\n+  u32 crc = Common::StartCRC32();\n+  mbedtls_md5_context md5_ctx{};\n+  mbedtls_md5_init(&md5_ctx);\n+  mbedtls_md5_starts_ret(&md5_ctx);\n+  XXH64_state_t* xxh_state = XXH64_createState();\n+  XXH64_reset(xxh_state, 0);\n+\n+  for (u64 i = 0; i < blocks_per_disc; i++)\n+  {\n+    if (i % 100 == 0)\n+    {\n+      const bool was_cancelled =\n+          !callback(Common::GetStringT("Converting"),\n+                    static_cast<float>(i) / static_cast<float>(blocks_per_disc));\n+      if (was_cancelled)\n+      {\n+        XXH64_freeState(xxh_state);\n+        mbedtls_md5_free(&md5_ctx);\n+        outfile.Close();\n+        File::Delete(outfile_path);', 'path': 'Source/Core/DiscIO/WbfsBlob.cpp', 'commit_id': '24b41d58df2315831b74f76b95417f2739d02f9d', 'original_commit_id': '24b41d58df2315831b74f76b95417f2739d02f9d', 'user': {'login': 'thethiny', 'id': 6018214, 'node_id': 'MDQ6VXNlcjYwMTgyMTQ=', 'avatar_url': 'https://avatars.githubusercontent.com/u/6018214?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/thethiny', 'html_url': 'https://github.com/thethiny', 'followers_url': 'https://api.github.com/users/thethiny/followers', 'following_url': 'https://api.github.com/users/thethiny/following{/other_user}', 'gists_url': 'https://api.github.com/users/thethiny/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/thethiny/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/thethiny/subscriptions', 'organizations_url': 'https://api.github.com/users/thethiny/orgs', 'repos_url': 'https://api.github.com/users/thethiny/repos', 'events_url': 'https://api.github.com/users/thethiny/events{/privacy}', 'received_events_url': 'https://api.github.com/users/thethiny/received_events', 'type': 'User', 'user_view_type': 'public', 'site_admin': False}, 'body': 'I was unaware of the concept of Scope Guards and RAII, thank you for this!', 'created_at': '2026-07-18T23:33:13Z', 'updated_at': '2026-07-18T23:33:13Z', 'html_url': 'https://github.com/dolphin-emu/dolphin/pull/14731#discussion_r3609413351', 'pull_request_url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/14731', '_links': {'self': {'href': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/comments/3609413351'}, 'html': {'href': 'https://github.com/dolphin-emu/dolphin/pull/14731#discussion_r3609413351'}, 'pull_request': {'href': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/14731'}}, 'reactions': {'url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/comments/3609413351/reactions', 'total_count': 0, '+1': 0, '-1': 0, 'laugh': 0, 'hooray': 0, 'confused': 0, 'heart': 0, 'rocket': 0, 'eyes': 0}, 'start_line': 491, 'original_start_line': 491, 'start_side': 'RIGHT', 'line': 494, 'original_line': 494, 'side': 'RIGHT', 'in_reply_to_id': 3609268698, 'author_association': 'NONE', 'original_position': 401, 'position': 401, 'subject_type': 'line'}, 'pull_request': {'url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/14731', 'id': 4056977334, 'node_id': 'PR_kwDOALCn2M7x0I-2', 'html_url': 'https://github.com/dolphin-emu/dolphin/pull/14731', 'diff_url': 'https://github.com/dolphin-emu/dolphin/pull/14731.diff', 'patch_url': 'https://github.com/dolphin-emu/dolphin/pull/14731.patch', 'issue_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/14731', 'number': 14731, 'state': 'open', 'locked': False, 'title': 'Convert To WBFS Support', 'user': {'login': 'thethiny', 'id': 6018214, 'node_id': 'MDQ6VXNlcjYwMTgyMTQ=', 'avatar_url': 'https://avatars.githubusercontent.com/u/6018214?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/thethiny', 'html_url': 'https://github.com/thethiny', 'followers_url': 'https://api.github.com/users/thethiny/followers', 'following_url': 'https://api.github.com/users/thethiny/following{/other_user}', 'gists_url': 'https://api.github.com/users/thethiny/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/thethiny/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/thethiny/subscriptions', 'organizations_url': 'https://api.github.com/users/thethiny/orgs', 'repos_url': 'https://api.github.com/users/thethiny/repos', 'events_url': 'https://api.github.com/users/thethiny/events{/privacy}', 'received_events_url': 'https://api.github.com/users/thethiny/received_events', 'type': 'User', 'user_view_type': 'public', 'site_admin': False}, 'body': "This PR introduces Conversion **to** WBFS support. WBFS is the format that is used by USB Loaders on a real Wii device.\r\n\r\n## Design decisions & hardcoded values\r\nThe writer uses fixed sector sizes that match what [libwbfs (the reference implementation by kwiirk)](https://github.com/kwiirk/wbfs/blob/master/libwbfs/libwbfs.c#L128-L134) computes for a standard single-layer Wii disc. These 2 hardcodes are stable and work correctly across all my testings.\r\n- HD sector shift: 9 (512 bytes)\r\n- WBFS sector shift: 21 (2 MiB)\r\nThese are not configurable via the UI. All existing WBFS tools use these values, and since the aim is to support USB Loaders then this has been tested and it is working on a real Wii.\r\n\r\nConverting from WBFS is not enabled. The existing `WbfsFileReader` reports `DataSizeType::UpperBound`, and `ShouldAllowConversion()` requires `Accurate`. I am able to support this but since it was hardcoded by the Dolphin team I thought a discussion is warranted.\r\n\r\n## Testing\r\n- Verified with DolphinTool header and DolphinTool verify\r\n- Verified with wit FILETYPE and wit DUMP (Wiimm's ISO Tools recognizes valid WBFS structure, partitions, encryption)\r\n- Tested ISO to WBFS and RVZ to WBFS conversions\r\n- Output file sizes match Wii Backup Manager when scrubbing is enabled (~0.1% difference), works when scrubbing is disabled.\r\n- Output WBFS files play correctly in Dolphin\r\n- Output WBFS files play correctly on a real Wii using USB Loader GX e25c4f3\r\n", 'created_at': '2026-07-15T01:16:25Z', 'updated_at': '2026-07-18T23:29:00Z', 'closed_at': None, 'merged_at': None, 'merge_commit_sha': '228f93416dd80eb09da834ad7852c8eaa4d9212b', 'assignees': [], 'requested_reviewers': [], 'requested_teams': [], 'labels': [], 'milestone': None, 'draft': False, 'commits_url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/14731/commits', 'review_comments_url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/14731/comments', 'review_comment_url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/comments{/number}', 'comments_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/14731/comments', 'statuses_url': 'https://api.github.com/repos/dolphin-emu/dolphin/statuses/24b41d58df2315831b74f76b95417f2739d02f9d', 'head': {'label': 'thethiny:wbfs-conversion', 'ref': 'wbfs-conversion', 'sha': '24b41d58df2315831b74f76b95417f2739d02f9d', 'user': {'login': 'thethiny', 'id': 6018214, 'node_id': 'MDQ6VXNlcjYwMTgyMTQ=', 'avatar_url': 'https://avatars.githubusercontent.com/u/6018214?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/thethiny', 'html_url': 'https://github.com/thethiny', 'followers_url': 'https://api.github.com/users/thethiny/followers', 'following_url': 'https://api.github.com/users/thethiny/following{/other_user}', 'gists_url': 'https://api.github.com/users/thethiny/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/thethiny/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/thethiny/subscriptions', 'organizations_url': 'https://api.github.com/users/thethiny/orgs', 'repos_url': 'https://api.github.com/users/thethiny/repos', 'events_url': 'https://api.github.com/users/thethiny/events{/privacy}', 'received_events_url': 'https://api.github.com/users/thethiny/received_events', 'type': 'User', 'user_view_type': 'public', 'site_admin': False}, 'repo': {'id': 1298654395, 'node_id': 'R_kgDOTWfkuw', 'name': 'dolphin', 'full_name': 'thethiny/dolphin', 'private': False, 'owner': {'login': 'thethiny', 'id': 6018214, 'node_id': 'MDQ6VXNlcjYwMTgyMTQ=', 'avatar_url': 'https://avatars.githubusercontent.com/u/6018214?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/thethiny', 'html_url': 'https://github.com/thethiny', 'followers_url': 'https://api.github.com/users/thethiny/followers', 'following_url': 'https://api.github.com/users/thethiny/following{/other_user}', 'gists_url': 'https://api.github.com/users/thethiny/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/thethiny/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/thethiny/subscriptions', 'organizations_url': 'https://api.github.com/users/thethiny/orgs', 'repos_url': 'https://api.github.com/users/thethiny/repos', 'events_url': 'https://api.github.com/users/thethiny/events{/privacy}', 'received_events_url': 'https://api.github.com/users/thethiny/received_events', 'type': 'User', 'user_view_type': 'public', 'site_admin': False}, 'html_url': 'https://github.com/thethiny/dolphin', 'description': 'Dolphin is a GameCube / Wii emulator, allowing you to play games for these two platforms on PC with improvements.', 'fork': True, 'url': 'https://api.github.com/repos/thethiny/dolphin', 'forks_url': 'https://api.github.com/repos/thethiny/dolphin/forks', 'keys_url': 'https://api.github.com/repos/thethiny/dolphin/keys{/key_id}', 'collaborators_url': 'https://api.github.com/repos/thethiny/dolphin/collaborators{/collaborator}', 'teams_url': 'https://api.github.com/repos/thethiny/dolphin/teams', 'hooks_url': 'https://api.github.com/repos/thethiny/dolphin/hooks', 'issue_events_url': 'https://api.github.com/repos/thethiny/dolphin/issues/events{/number}', 'events_url': 'https://api.github.com/repos/thethiny/dolphin/events', 'assignees_url': 'https://api.github.com/repos/thethiny/dolphin/assignees{/user}', 'branches_url': 'https://api.github.com/repos/thethiny/dolphin/branches{/branch}', 'tags_url': 'https://api.github.com/repos/thethiny/dolphin/tags', 'blobs_url': 'https://api.github.com/repos/thethiny/dolphin/git/blobs{/sha}', 'git_tags_url': 'https://api.github.com/repos/thethiny/dolphin/git/tags{/sha}', 'git_refs_url': 'https://api.github.com/repos/thethiny/dolphin/git/refs{/sha}', 'trees_url': 'https://api.github.com/repos/thethiny/dolphin/git/trees{/sha}', 'statuses_url': 'https://api.github.com/repos/thethiny/dolphin/statuses/{sha}', 'languages_url': 'https://api.github.com/repos/thethiny/dolphin/languages', 'stargazers_url': 'https://api.github.com/repos/thethiny/dolphin/stargazers', 'contributors_url': 'https://api.github.com/repos/thethiny/dolphin/contributors', 'subscribers_url': 'https://api.github.com/repos/thethiny/dolphin/subscribers', 'subscription_url': 'https://api.github.com/repos/thethiny/dolphin/subscription', 'commits_url': 'https://api.github.com/repos/thethiny/dolphin/commits{/sha}', 'git_commits_url': 'https://api.github.com/repos/thethiny/dolphin/git/commits{/sha}', 'comments_url': 'https://api.github.com/repos/thethiny/dolphin/comments{/number}', 'issue_comment_url': 'https://api.github.com/repos/thethiny/dolphin/issues/comments{/number}', 'contents_url': 'https://api.github.com/repos/thethiny/dolphin/contents/{+path}', 'compare_url': 'https://api.github.com/repos/thethiny/dolphin/compare/{base}...{head}', 'merges_url': 'https://api.github.com/repos/thethiny/dolphin/merges', 'archive_url': 'https://api.github.com/repos/thethiny/dolphin/{archive_format}{/ref}', 'downloads_url': 'https://api.github.com/repos/thethiny/dolphin/downloads', 'issues_url': 'https://api.github.com/repos/thethiny/dolphin/issues{/number}', 'pulls_url': 'https://api.github.com/repos/thethiny/dolphin/pulls{/number}', 'milestones_url': 'https://api.github.com/repos/thethiny/dolphin/milestones{/number}', 'notifications_url': 'https://api.github.com/repos/thethiny/dolphin/notifications{?since,all,participating}', 'labels_url': 'https://api.github.com/repos/thethiny/dolphin/labels{/name}', 'releases_url': 'https://api.github.com/repos/thethiny/dolphin/releases{/id}', 'deployments_url': 'https://api.github.com/repos/thethiny/dolphin/deployments', 'created_at': '2026-07-12T22:09:13Z', 'updated_at': '2026-07-12T22:09:13Z', 'pushed_at': '2026-07-18T20:35:03Z', 'git_url': 'git://github.com/thethiny/dolphin.git', 'ssh_url': 'git@github.com:thethiny/dolphin.git', 'clone_url': 'https://github.com/thethiny/dolphin.git', 'svn_url': 'https://github.com/thethiny/dolphin', 'homepage': 'https://dolphin-emu.org', 'size': 515471, 'stargazers_count': 0, 'watchers_count': 0, 'language': None, 'has_issues': False, 'has_projects': True, 'has_downloads': True, 'has_wiki': True, 'has_pages': False, 'has_discussions': False, 'forks_count': 0, 'mirror_url': None, 'archived': False, 'disabled': False, 'open_issues_count': 0, 'license': {'key': 'other', 'name': 'Other', 'spdx_id': 'NOASSERTION', 'url': None, 'node_id': 'MDc6TGljZW5zZTA='}, 'allow_forking': True, 'is_template': False, 'web_commit_signoff_required': False, 'has_pull_requests': True, 'pull_request_creation_policy': 'all', 'topics': [], 'visibility': 'public', 'forks': 0, 'open_issues': 0, 'watchers': 0, 'default_branch': 'master', 'allow_squash_merge': True, 'allow_merge_commit': True, 'allow_rebase_merge': True, 'allow_auto_merge': False, 'delete_branch_on_merge': False, 'allow_update_branch': False, 'use_squash_pr_title_as_default': False, 'squash_merge_commit_message': 'COMMIT_MESSAGES', 'squash_merge_commit_title': 'COMMIT_OR_PR_TITLE', 'merge_commit_message': 'PR_TITLE', 'merge_commit_title': 'MERGE_MESSAGE'}}, 'base': {'label': 'dolphin-emu:master', 'ref': 'master', 'sha': 'd3b2943807dd0073f7767947466dd73cccfef319', 'user': {'login': 'dolphin-emu', 'id': 5050316, 'node_id': 'MDEyOk9yZ2FuaXphdGlvbjUwNTAzMTY=', 'avatar_url': 'https://avatars.githubusercontent.com/u/5050316?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/dolphin-emu', 'html_url': 'https://github.com/dolphin-emu', 'followers_url': 'https://api.github.com/users/dolphin-emu/followers', 'following_url': 'https://api.github.com/users/dolphin-emu/following{/other_user}', 'gists_url': 'https://api.github.com/users/dolphin-emu/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/dolphin-emu/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/dolphin-emu/subscriptions', 'organizations_url': 'https://api.github.com/users/dolphin-emu/orgs', 'repos_url': 'https://api.github.com/users/dolphin-emu/repos', 'events_url': 'https://api.github.com/users/dolphin-emu/events{/privacy}', 'received_events_url': 'https://api.github.com/users/dolphin-emu/received_events', 'type': 'Organization', 'user_view_type': 'public', 'site_admin': False}, 'repo': {'id': 11577304, 'node_id': 'MDEwOlJlcG9zaXRvcnkxMTU3NzMwNA==', 'name': 'dolphin', 'full_name': 'dolphin-emu/dolphin', 'private': False, 'owner': {'login': 'dolphin-emu', 'id': 5050316, 'node_id': 'MDEyOk9yZ2FuaXphdGlvbjUwNTAzMTY=', 'avatar_url': 'https://avatars.githubusercontent.com/u/5050316?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/dolphin-emu', 'html_url': 'https://github.com/dolphin-emu', 'followers_url': 'https://api.github.com/users/dolphin-emu/followers', 'following_url': 'https://api.github.com/users/dolphin-emu/following{/other_user}', 'gists_url': 'https://api.github.com/users/dolphin-emu/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/dolphin-emu/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/dolphin-emu/subscriptions', 'organizations_url': 'https://api.github.com/users/dolphin-emu/orgs', 'repos_url': 'https://api.github.com/users/dolphin-emu/repos', 'events_url': 'https://api.github.com/users/dolphin-emu/events{/privacy}', 'received_events_url': 'https://api.github.com/users/dolphin-emu/received_events', 'type': 'Organization', 'user_view_type': 'public', 'site_admin': False}, 'html_url': 'https://github.com/dolphin-emu/dolphin', 'description': 'Dolphin is a GameCube / Wii emulator, allowing you to play games for these two platforms on PC with improvements.', 'fork': False, 'url': 'https://api.github.com/repos/dolphin-emu/dolphin', 'forks_url': 'https://api.github.com/repos/dolphin-emu/dolphin/forks', 'keys_url': 'https://api.github.com/repos/dolphin-emu/dolphin/keys{/key_id}', 'collaborators_url': 'https://api.github.com/repos/dolphin-emu/dolphin/collaborators{/collaborator}', 'teams_url': 'https://api.github.com/repos/dolphin-emu/dolphin/teams', 'hooks_url': 'https://api.github.com/repos/dolphin-emu/dolphin/hooks', 'issue_events_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/events{/number}', 'events_url': 'https://api.github.com/repos/dolphin-emu/dolphin/events', 'assignees_url': 'https://api.github.com/repos/dolphin-emu/dolphin/assignees{/user}', 'branches_url': 'https://api.github.com/repos/dolphin-emu/dolphin/branches{/branch}', 'tags_url': 'https://api.github.com/repos/dolphin-emu/dolphin/tags', 'blobs_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/blobs{/sha}', 'git_tags_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/tags{/sha}', 'git_refs_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/refs{/sha}', 'trees_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/trees{/sha}', 'statuses_url': 'https://api.github.com/repos/dolphin-emu/dolphin/statuses/{sha}', 'languages_url': 'https://api.github.com/repos/dolphin-emu/dolphin/languages', 'stargazers_url': 'https://api.github.com/repos/dolphin-emu/dolphin/stargazers', 'contributors_url': 'https://api.github.com/repos/dolphin-emu/dolphin/contributors', 'subscribers_url': 'https://api.github.com/repos/dolphin-emu/dolphin/subscribers', 'subscription_url': 'https://api.github.com/repos/dolphin-emu/dolphin/subscription', 'commits_url': 'https://api.github.com/repos/dolphin-emu/dolphin/commits{/sha}', 'git_commits_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/commits{/sha}', 'comments_url': 'https://api.github.com/repos/dolphin-emu/dolphin/comments{/number}', 'issue_comment_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/comments{/number}', 'contents_url': 'https://api.github.com/repos/dolphin-emu/dolphin/contents/{+path}', 'compare_url': 'https://api.github.com/repos/dolphin-emu/dolphin/compare/{base}...{head}', 'merges_url': 'https://api.github.com/repos/dolphin-emu/dolphin/merges', 'archive_url': 'https://api.github.com/repos/dolphin-emu/dolphin/{archive_format}{/ref}', 'downloads_url': 'https://api.github.com/repos/dolphin-emu/dolphin/downloads', 'issues_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues{/number}', 'pulls_url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls{/number}', 'milestones_url': 'https://api.github.com/repos/dolphin-emu/dolphin/milestones{/number}', 'notifications_url': 'https://api.github.com/repos/dolphin-emu/dolphin/notifications{?since,all,participating}', 'labels_url': 'https://api.github.com/repos/dolphin-emu/dolphin/labels{/name}', 'releases_url': 'https://api.github.com/repos/dolphin-emu/dolphin/releases{/id}', 'deployments_url': 'https://api.github.com/repos/dolphin-emu/dolphin/deployments', 'created_at': '2013-07-22T09:07:57Z', 'updated_at': '2026-07-18T23:13:54Z', 'pushed_at': '2026-07-18T10:34:54Z', 'git_url': 'git://github.com/dolphin-emu/dolphin.git', 'ssh_url': 'git@github.com:dolphin-emu/dolphin.git', 'clone_url': 'https://github.com/dolphin-emu/dolphin.git', 'svn_url': 'https://github.com/dolphin-emu/dolphin', 'homepage': 'https://dolphin-emu.org', 'size': 558448, 'stargazers_count': 15273, 'watchers_count': 15273, 'language': 'C++', 'has_issues': False, 'has_projects': False, 'has_downloads': True, 'has_wiki': True, 'has_pages': False, 'has_discussions': False, 'forks_count': 3162, 'mirror_url': None, 'archived': False, 'disabled': False, 'open_issues_count': 446, 'license': {'key': 'other', 'name': 'Other', 'spdx_id': 'NOASSERTION', 'url': None, 'node_id': 'MDc6TGljZW5zZTA='}, 'allow_forking': True, 'is_template': False, 'web_commit_signoff_required': False, 'has_pull_requests': True, 'pull_request_creation_policy': 'all', 'topics': ['cpp', 'emulation', 'emulator', 'gamecube', 'wii'], 'visibility': 'public', 'forks': 3162, 'open_issues': 446, 'watchers': 15273, 'default_branch': 'master', 'allow_squash_merge': False, 'allow_merge_commit': True, 'allow_rebase_merge': False, 'allow_auto_merge': False, 'delete_branch_on_merge': False, 'allow_update_branch': False, 'use_squash_pr_title_as_default': False, 'squash_merge_commit_message': 'COMMIT_MESSAGES', 'squash_merge_commit_title': 'COMMIT_OR_PR_TITLE', 'merge_commit_message': 'PR_TITLE', 'merge_commit_title': 'MERGE_MESSAGE'}}, '_links': {'self': {'href': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/14731'}, 'html': {'href': 'https://github.com/dolphin-emu/dolphin/pull/14731'}, 'issue': {'href': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/14731'}, 'comments': {'href': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/14731/comments'}, 'review_comments': {'href': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/14731/comments'}, 'review_comment': {'href': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/comments{/number}'}, 'commits': {'href': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/14731/commits'}, 'statuses': {'href': 'https://api.github.com/repos/dolphin-emu/dolphin/statuses/24b41d58df2315831b74f76b95417f2739d02f9d'}}, 'author_association': 'NONE', 'auto_merge': None, 'assignee': None, 'active_lock_reason': None}, 'repository': {'id': 11577304, 'node_id': 'MDEwOlJlcG9zaXRvcnkxMTU3NzMwNA==', 'name': 'dolphin', 'full_name': 'dolphin-emu/dolphin', 'private': False, 'owner': {'login': 'dolphin-emu', 'id': 5050316, 'node_id': 'MDEyOk9yZ2FuaXphdGlvbjUwNTAzMTY=', 'avatar_url': 'https://avatars.githubusercontent.com/u/5050316?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/dolphin-emu', 'html_url': 'https://github.com/dolphin-emu', 'followers_url': 'https://api.github.com/users/dolphin-emu/followers', 'following_url': 'https://api.github.com/users/dolphin-emu/following{/other_user}', 'gists_url': 'https://api.github.com/users/dolphin-emu/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/dolphin-emu/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/dolphin-emu/subscriptions', 'organizations_url': 'https://api.github.com/users/dolphin-emu/orgs', 'repos_url': 'https://api.github.com/users/dolphin-emu/repos', 'events_url': 'https://api.github.com/users/dolphin-emu/events{/privacy}', 'received_events_url': 'https://api.github.com/users/dolphin-emu/received_events', 'type': 'Organization', 'user_view_type': 'public', 'site_admin': False}, 'html_url': 'https://github.com/dolphin-emu/dolphin', 'description': 'Dolphin is a GameCube / Wii emulator, allowing you to play games for these two platforms on PC with improvements.', 'fork': False, 'url': 'https://api.github.com/repos/dolphin-emu/dolphin', 'forks_url': 'https://api.github.com/repos/dolphin-emu/dolphin/forks', 'keys_url': 'https://api.github.com/repos/dolphin-emu/dolphin/keys{/key_id}', 'collaborators_url': 'https://api.github.com/repos/dolphin-emu/dolphin/collaborators{/collaborator}', 'teams_url': 'https://api.github.com/repos/dolphin-emu/dolphin/teams', 'hooks_url': 'https://api.github.com/repos/dolphin-emu/dolphin/hooks', 'issue_events_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/events{/number}', 'events_url': 'https://api.github.com/repos/dolphin-emu/dolphin/events', 'assignees_url': 'https://api.github.com/repos/dolphin-emu/dolphin/assignees{/user}', 'branches_url': 'https://api.github.com/repos/dolphin-emu/dolphin/branches{/branch}', 'tags_url': 'https://api.github.com/repos/dolphin-emu/dolphin/tags', 'blobs_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/blobs{/sha}', 'git_tags_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/tags{/sha}', 'git_refs_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/refs{/sha}', 'trees_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/trees{/sha}', 'statuses_url': 'https://api.github.com/repos/dolphin-emu/dolphin/statuses/{sha}', 'languages_url': 'https://api.github.com/repos/dolphin-emu/dolphin/languages', 'stargazers_url': 'https://api.github.com/repos/dolphin-emu/dolphin/stargazers', 'contributors_url': 'https://api.github.com/repos/dolphin-emu/dolphin/contributors', 'subscribers_url': 'https://api.github.com/repos/dolphin-emu/dolphin/subscribers', 'subscription_url': 'https://api.github.com/repos/dolphin-emu/dolphin/subscription', 'commits_url': 'https://api.github.com/repos/dolphin-emu/dolphin/commits{/sha}', 'git_commits_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/commits{/sha}', 'comments_url': 'https://api.github.com/repos/dolphin-emu/dolphin/comments{/number}', 'issue_comment_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/comments{/number}', 'contents_url': 'https://api.github.com/repos/dolphin-emu/dolphin/contents/{+path}', 'compare_url': 'https://api.github.com/repos/dolphin-emu/dolphin/compare/{base}...{head}', 'merges_url': 'https://api.github.com/repos/dolphin-emu/dolphin/merges', 'archive_url': 'https://api.github.com/repos/dolphin-emu/dolphin/{archive_format}{/ref}', 'downloads_url': 'https://api.github.com/repos/dolphin-emu/dolphin/downloads', 'issues_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues{/number}', 'pulls_url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls{/number}', 'milestones_url': 'https://api.github.com/repos/dolphin-emu/dolphin/milestones{/number}', 'notifications_url': 'https://api.github.com/repos/dolphin-emu/dolphin/notifications{?since,all,participating}', 'labels_url': 'https://api.github.com/repos/dolphin-emu/dolphin/labels{/name}', 'releases_url': 'https://api.github.com/repos/dolphin-emu/dolphin/releases{/id}', 'deployments_url': 'https://api.github.com/repos/dolphin-emu/dolphin/deployments', 'created_at': '2013-07-22T09:07:57Z', 'updated_at': '2026-07-18T23:13:54Z', 'pushed_at': '2026-07-18T10:34:54Z', 'git_url': 'git://github.com/dolphin-emu/dolphin.git', 'ssh_url': 'git@github.com:dolphin-emu/dolphin.git', 'clone_url': 'https://github.com/dolphin-emu/dolphin.git', 'svn_url': 'https://github.com/dolphin-emu/dolphin', 'homepage': 'https://dolphin-emu.org', 'size': 558448, 'stargazers_count': 15273, 'watchers_count': 15273, 'language': 'C++', 'has_issues': False, 'has_projects': False, 'has_downloads': True, 'has_wiki': True, 'has_pages': False, 'has_discussions': False, 'forks_count': 3162, 'mirror_url': None, 'archived': False, 'disabled': False, 'open_issues_count': 446, 'license': {'key': 'other', 'name': 'Other', 'spdx_id': 'NOASSERTION', 'url': None, 'node_id': 'MDc6TGljZW5zZTA='}, 'allow_forking': True, 'is_template': False, 'web_commit_signoff_required': False, 'has_pull_requests': True, 'pull_request_creation_policy': 'all', 'topics': ['cpp', 'emulation', 'emulator', 'gamecube', 'wii'], 'visibility': 'public', 'forks': 3162, 'open_issues': 446, 'watchers': 15273, 'default_branch': 'master', 'custom_properties': {}}, 'organization': {'login': 'dolphin-emu', 'id': 5050316, 'node_id': 'MDEyOk9yZ2FuaXphdGlvbjUwNTAzMTY=', 'url': 'https://api.github.com/orgs/dolphin-emu', 'repos_url': 'https://api.github.com/orgs/dolphin-emu/repos', 'events_url': 'https://api.github.com/orgs/dolphin-emu/events', 'hooks_url': 'https://api.github.com/orgs/dolphin-emu/hooks', 'issues_url': 'https://api.github.com/orgs/dolphin-emu/issues', 'members_url': 'https://api.github.com/orgs/dolphin-emu/members{/member}', 'public_members_url': 'https://api.github.com/orgs/dolphin-emu/public_members{/member}', 'avatar_url': 'https://avatars.githubusercontent.com/u/5050316?v=4', 'description': ''}, 'sender': {'login': 'thethiny', 'id': 6018214, 'node_id': 'MDQ6VXNlcjYwMTgyMTQ=', 'avatar_url': 'https://avatars.githubusercontent.com/u/6018214?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/thethiny', 'html_url': 'https://github.com/thethiny', 'followers_url': 'https://api.github.com/users/thethiny/followers', 'following_url': 'https://api.github.com/users/thethiny/following{/other_user}', 'gists_url': 'https://api.github.com/users/thethiny/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/thethiny/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/thethiny/subscriptions', 'organizations_url': 'https://api.github.com/users/thethiny/orgs', 'repos_url': 'https://api.github.com/users/thethiny/repos', 'events_url': 'https://api.github.com/users/thethiny/events{/privacy}', 'received_events_url': 'https://api.github.com/users/thethiny/received_events', 'type': 'User', 'user_view_type': 'public', 'site_admin': False}, 'installation': {'id': 35437981, 'node_id': 'MDIzOkludGVncmF0aW9uSW5zdGFsbGF0aW9uMzU0Mzc5ODE='}}, 'type': 'raw_gh_hook'}
2026-07-18T23:33:15.219140	{'source': 'webserver', 'gh_type': 'pull_request_review', 'raw': {'action': 'submitted', 'review': {'id': 4729496492, 'node_id': 'PRR_kwDOALCn2M8AAAABGeZjrA', 'user': {'login': 'thethiny', 'id': 6018214, 'node_id': 'MDQ6VXNlcjYwMTgyMTQ=', 'avatar_url': 'https://avatars.githubusercontent.com/u/6018214?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/thethiny', 'html_url': 'https://github.com/thethiny', 'followers_url': 'https://api.github.com/users/thethiny/followers', 'following_url': 'https://api.github.com/users/thethiny/following{/other_user}', 'gists_url': 'https://api.github.com/users/thethiny/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/thethiny/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/thethiny/subscriptions', 'organizations_url': 'https://api.github.com/users/thethiny/orgs', 'repos_url': 'https://api.github.com/users/thethiny/repos', 'events_url': 'https://api.github.com/users/thethiny/events{/privacy}', 'received_events_url': 'https://api.github.com/users/thethiny/received_events', 'type': 'User', 'user_view_type': 'public', 'site_admin': False}, 'body': None, 'commit_id': '24b41d58df2315831b74f76b95417f2739d02f9d', 'state': 'commented', 'html_url': 'https://github.com/dolphin-emu/dolphin/pull/14731#pullrequestreview-4729496492', 'pull_request_url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/14731', '_links': {'html': {'href': 'https://github.com/dolphin-emu/dolphin/pull/14731#pullrequestreview-4729496492'}, 'pull_request': {'href': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/14731'}}, 'submitted_at': '2026-07-18T23:33:13Z', 'updated_at': '2026-07-18T23:33:13Z', 'author_association': 'NONE'}, 'pull_request': {'url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/14731', 'id': 4056977334, 'node_id': 'PR_kwDOALCn2M7x0I-2', 'html_url': 'https://github.com/dolphin-emu/dolphin/pull/14731', 'diff_url': 'https://github.com/dolphin-emu/dolphin/pull/14731.diff', 'patch_url': 'https://github.com/dolphin-emu/dolphin/pull/14731.patch', 'issue_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/14731', 'number': 14731, 'state': 'open', 'locked': False, 'title': 'Convert To WBFS Support', 'user': {'login': 'thethiny', 'id': 6018214, 'node_id': 'MDQ6VXNlcjYwMTgyMTQ=', 'avatar_url': 'https://avatars.githubusercontent.com/u/6018214?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/thethiny', 'html_url': 'https://github.com/thethiny', 'followers_url': 'https://api.github.com/users/thethiny/followers', 'following_url': 'https://api.github.com/users/thethiny/following{/other_user}', 'gists_url': 'https://api.github.com/users/thethiny/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/thethiny/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/thethiny/subscriptions', 'organizations_url': 'https://api.github.com/users/thethiny/orgs', 'repos_url': 'https://api.github.com/users/thethiny/repos', 'events_url': 'https://api.github.com/users/thethiny/events{/privacy}', 'received_events_url': 'https://api.github.com/users/thethiny/received_events', 'type': 'User', 'user_view_type': 'public', 'site_admin': False}, 'body': "This PR introduces Conversion **to** WBFS support. WBFS is the format that is used by USB Loaders on a real Wii device.\r\n\r\n## Design decisions & hardcoded values\r\nThe writer uses fixed sector sizes that match what [libwbfs (the reference implementation by kwiirk)](https://github.com/kwiirk/wbfs/blob/master/libwbfs/libwbfs.c#L128-L134) computes for a standard single-layer Wii disc. These 2 hardcodes are stable and work correctly across all my testings.\r\n- HD sector shift: 9 (512 bytes)\r\n- WBFS sector shift: 21 (2 MiB)\r\nThese are not configurable via the UI. All existing WBFS tools use these values, and since the aim is to support USB Loaders then this has been tested and it is working on a real Wii.\r\n\r\nConverting from WBFS is not enabled. The existing `WbfsFileReader` reports `DataSizeType::UpperBound`, and `ShouldAllowConversion()` requires `Accurate`. I am able to support this but since it was hardcoded by the Dolphin team I thought a discussion is warranted.\r\n\r\n## Testing\r\n- Verified with DolphinTool header and DolphinTool verify\r\n- Verified with wit FILETYPE and wit DUMP (Wiimm's ISO Tools recognizes valid WBFS structure, partitions, encryption)\r\n- Tested ISO to WBFS and RVZ to WBFS conversions\r\n- Output file sizes match Wii Backup Manager when scrubbing is enabled (~0.1% difference), works when scrubbing is disabled.\r\n- Output WBFS files play correctly in Dolphin\r\n- Output WBFS files play correctly on a real Wii using USB Loader GX e25c4f3\r\n", 'created_at': '2026-07-15T01:16:25Z', 'updated_at': '2026-07-18T23:29:00Z', 'closed_at': None, 'merged_at': None, 'merge_commit_sha': '228f93416dd80eb09da834ad7852c8eaa4d9212b', 'assignees': [], 'requested_reviewers': [], 'requested_teams': [], 'labels': [], 'milestone': None, 'draft': False, 'commits_url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/14731/commits', 'review_comments_url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/14731/comments', 'review_comment_url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/comments{/number}', 'comments_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/14731/comments', 'statuses_url': 'https://api.github.com/repos/dolphin-emu/dolphin/statuses/24b41d58df2315831b74f76b95417f2739d02f9d', 'head': {'label': 'thethiny:wbfs-conversion', 'ref': 'wbfs-conversion', 'sha': '24b41d58df2315831b74f76b95417f2739d02f9d', 'user': {'login': 'thethiny', 'id': 6018214, 'node_id': 'MDQ6VXNlcjYwMTgyMTQ=', 'avatar_url': 'https://avatars.githubusercontent.com/u/6018214?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/thethiny', 'html_url': 'https://github.com/thethiny', 'followers_url': 'https://api.github.com/users/thethiny/followers', 'following_url': 'https://api.github.com/users/thethiny/following{/other_user}', 'gists_url': 'https://api.github.com/users/thethiny/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/thethiny/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/thethiny/subscriptions', 'organizations_url': 'https://api.github.com/users/thethiny/orgs', 'repos_url': 'https://api.github.com/users/thethiny/repos', 'events_url': 'https://api.github.com/users/thethiny/events{/privacy}', 'received_events_url': 'https://api.github.com/users/thethiny/received_events', 'type': 'User', 'user_view_type': 'public', 'site_admin': False}, 'repo': {'id': 1298654395, 'node_id': 'R_kgDOTWfkuw', 'name': 'dolphin', 'full_name': 'thethiny/dolphin', 'private': False, 'owner': {'login': 'thethiny', 'id': 6018214, 'node_id': 'MDQ6VXNlcjYwMTgyMTQ=', 'avatar_url': 'https://avatars.githubusercontent.com/u/6018214?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/thethiny', 'html_url': 'https://github.com/thethiny', 'followers_url': 'https://api.github.com/users/thethiny/followers', 'following_url': 'https://api.github.com/users/thethiny/following{/other_user}', 'gists_url': 'https://api.github.com/users/thethiny/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/thethiny/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/thethiny/subscriptions', 'organizations_url': 'https://api.github.com/users/thethiny/orgs', 'repos_url': 'https://api.github.com/users/thethiny/repos', 'events_url': 'https://api.github.com/users/thethiny/events{/privacy}', 'received_events_url': 'https://api.github.com/users/thethiny/received_events', 'type': 'User', 'user_view_type': 'public', 'site_admin': False}, 'html_url': 'https://github.com/thethiny/dolphin', 'description': 'Dolphin is a GameCube / Wii emulator, allowing you to play games for these two platforms on PC with improvements.', 'fork': True, 'url': 'https://api.github.com/repos/thethiny/dolphin', 'forks_url': 'https://api.github.com/repos/thethiny/dolphin/forks', 'keys_url': 'https://api.github.com/repos/thethiny/dolphin/keys{/key_id}', 'collaborators_url': 'https://api.github.com/repos/thethiny/dolphin/collaborators{/collaborator}', 'teams_url': 'https://api.github.com/repos/thethiny/dolphin/teams', 'hooks_url': 'https://api.github.com/repos/thethiny/dolphin/hooks', 'issue_events_url': 'https://api.github.com/repos/thethiny/dolphin/issues/events{/number}', 'events_url': 'https://api.github.com/repos/thethiny/dolphin/events', 'assignees_url': 'https://api.github.com/repos/thethiny/dolphin/assignees{/user}', 'branches_url': 'https://api.github.com/repos/thethiny/dolphin/branches{/branch}', 'tags_url': 'https://api.github.com/repos/thethiny/dolphin/tags', 'blobs_url': 'https://api.github.com/repos/thethiny/dolphin/git/blobs{/sha}', 'git_tags_url': 'https://api.github.com/repos/thethiny/dolphin/git/tags{/sha}', 'git_refs_url': 'https://api.github.com/repos/thethiny/dolphin/git/refs{/sha}', 'trees_url': 'https://api.github.com/repos/thethiny/dolphin/git/trees{/sha}', 'statuses_url': 'https://api.github.com/repos/thethiny/dolphin/statuses/{sha}', 'languages_url': 'https://api.github.com/repos/thethiny/dolphin/languages', 'stargazers_url': 'https://api.github.com/repos/thethiny/dolphin/stargazers', 'contributors_url': 'https://api.github.com/repos/thethiny/dolphin/contributors', 'subscribers_url': 'https://api.github.com/repos/thethiny/dolphin/subscribers', 'subscription_url': 'https://api.github.com/repos/thethiny/dolphin/subscription', 'commits_url': 'https://api.github.com/repos/thethiny/dolphin/commits{/sha}', 'git_commits_url': 'https://api.github.com/repos/thethiny/dolphin/git/commits{/sha}', 'comments_url': 'https://api.github.com/repos/thethiny/dolphin/comments{/number}', 'issue_comment_url': 'https://api.github.com/repos/thethiny/dolphin/issues/comments{/number}', 'contents_url': 'https://api.github.com/repos/thethiny/dolphin/contents/{+path}', 'compare_url': 'https://api.github.com/repos/thethiny/dolphin/compare/{base}...{head}', 'merges_url': 'https://api.github.com/repos/thethiny/dolphin/merges', 'archive_url': 'https://api.github.com/repos/thethiny/dolphin/{archive_format}{/ref}', 'downloads_url': 'https://api.github.com/repos/thethiny/dolphin/downloads', 'issues_url': 'https://api.github.com/repos/thethiny/dolphin/issues{/number}', 'pulls_url': 'https://api.github.com/repos/thethiny/dolphin/pulls{/number}', 'milestones_url': 'https://api.github.com/repos/thethiny/dolphin/milestones{/number}', 'notifications_url': 'https://api.github.com/repos/thethiny/dolphin/notifications{?since,all,participating}', 'labels_url': 'https://api.github.com/repos/thethiny/dolphin/labels{/name}', 'releases_url': 'https://api.github.com/repos/thethiny/dolphin/releases{/id}', 'deployments_url': 'https://api.github.com/repos/thethiny/dolphin/deployments', 'created_at': '2026-07-12T22:09:13Z', 'updated_at': '2026-07-12T22:09:13Z', 'pushed_at': '2026-07-18T20:35:03Z', 'git_url': 'git://github.com/thethiny/dolphin.git', 'ssh_url': 'git@github.com:thethiny/dolphin.git', 'clone_url': 'https://github.com/thethiny/dolphin.git', 'svn_url': 'https://github.com/thethiny/dolphin', 'homepage': 'https://dolphin-emu.org', 'size': 515471, 'stargazers_count': 0, 'watchers_count': 0, 'language': None, 'has_issues': False, 'has_projects': True, 'has_downloads': True, 'has_wiki': True, 'has_pages': False, 'has_discussions': False, 'forks_count': 0, 'mirror_url': None, 'archived': False, 'disabled': False, 'open_issues_count': 0, 'license': {'key': 'other', 'name': 'Other', 'spdx_id': 'NOASSERTION', 'url': None, 'node_id': 'MDc6TGljZW5zZTA='}, 'allow_forking': True, 'is_template': False, 'web_commit_signoff_required': False, 'has_pull_requests': True, 'pull_request_creation_policy': 'all', 'topics': [], 'visibility': 'public', 'forks': 0, 'open_issues': 0, 'watchers': 0, 'default_branch': 'master', 'allow_squash_merge': True, 'allow_merge_commit': True, 'allow_rebase_merge': True, 'allow_auto_merge': False, 'delete_branch_on_merge': False, 'allow_update_branch': False, 'use_squash_pr_title_as_default': False, 'squash_merge_commit_message': 'COMMIT_MESSAGES', 'squash_merge_commit_title': 'COMMIT_OR_PR_TITLE', 'merge_commit_message': 'PR_TITLE', 'merge_commit_title': 'MERGE_MESSAGE'}}, 'base': {'label': 'dolphin-emu:master', 'ref': 'master', 'sha': 'd3b2943807dd0073f7767947466dd73cccfef319', 'user': {'login': 'dolphin-emu', 'id': 5050316, 'node_id': 'MDEyOk9yZ2FuaXphdGlvbjUwNTAzMTY=', 'avatar_url': 'https://avatars.githubusercontent.com/u/5050316?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/dolphin-emu', 'html_url': 'https://github.com/dolphin-emu', 'followers_url': 'https://api.github.com/users/dolphin-emu/followers', 'following_url': 'https://api.github.com/users/dolphin-emu/following{/other_user}', 'gists_url': 'https://api.github.com/users/dolphin-emu/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/dolphin-emu/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/dolphin-emu/subscriptions', 'organizations_url': 'https://api.github.com/users/dolphin-emu/orgs', 'repos_url': 'https://api.github.com/users/dolphin-emu/repos', 'events_url': 'https://api.github.com/users/dolphin-emu/events{/privacy}', 'received_events_url': 'https://api.github.com/users/dolphin-emu/received_events', 'type': 'Organization', 'user_view_type': 'public', 'site_admin': False}, 'repo': {'id': 11577304, 'node_id': 'MDEwOlJlcG9zaXRvcnkxMTU3NzMwNA==', 'name': 'dolphin', 'full_name': 'dolphin-emu/dolphin', 'private': False, 'owner': {'login': 'dolphin-emu', 'id': 5050316, 'node_id': 'MDEyOk9yZ2FuaXphdGlvbjUwNTAzMTY=', 'avatar_url': 'https://avatars.githubusercontent.com/u/5050316?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/dolphin-emu', 'html_url': 'https://github.com/dolphin-emu', 'followers_url': 'https://api.github.com/users/dolphin-emu/followers', 'following_url': 'https://api.github.com/users/dolphin-emu/following{/other_user}', 'gists_url': 'https://api.github.com/users/dolphin-emu/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/dolphin-emu/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/dolphin-emu/subscriptions', 'organizations_url': 'https://api.github.com/users/dolphin-emu/orgs', 'repos_url': 'https://api.github.com/users/dolphin-emu/repos', 'events_url': 'https://api.github.com/users/dolphin-emu/events{/privacy}', 'received_events_url': 'https://api.github.com/users/dolphin-emu/received_events', 'type': 'Organization', 'user_view_type': 'public', 'site_admin': False}, 'html_url': 'https://github.com/dolphin-emu/dolphin', 'description': 'Dolphin is a GameCube / Wii emulator, allowing you to play games for these two platforms on PC with improvements.', 'fork': False, 'url': 'https://api.github.com/repos/dolphin-emu/dolphin', 'forks_url': 'https://api.github.com/repos/dolphin-emu/dolphin/forks', 'keys_url': 'https://api.github.com/repos/dolphin-emu/dolphin/keys{/key_id}', 'collaborators_url': 'https://api.github.com/repos/dolphin-emu/dolphin/collaborators{/collaborator}', 'teams_url': 'https://api.github.com/repos/dolphin-emu/dolphin/teams', 'hooks_url': 'https://api.github.com/repos/dolphin-emu/dolphin/hooks', 'issue_events_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/events{/number}', 'events_url': 'https://api.github.com/repos/dolphin-emu/dolphin/events', 'assignees_url': 'https://api.github.com/repos/dolphin-emu/dolphin/assignees{/user}', 'branches_url': 'https://api.github.com/repos/dolphin-emu/dolphin/branches{/branch}', 'tags_url': 'https://api.github.com/repos/dolphin-emu/dolphin/tags', 'blobs_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/blobs{/sha}', 'git_tags_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/tags{/sha}', 'git_refs_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/refs{/sha}', 'trees_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/trees{/sha}', 'statuses_url': 'https://api.github.com/repos/dolphin-emu/dolphin/statuses/{sha}', 'languages_url': 'https://api.github.com/repos/dolphin-emu/dolphin/languages', 'stargazers_url': 'https://api.github.com/repos/dolphin-emu/dolphin/stargazers', 'contributors_url': 'https://api.github.com/repos/dolphin-emu/dolphin/contributors', 'subscribers_url': 'https://api.github.com/repos/dolphin-emu/dolphin/subscribers', 'subscription_url': 'https://api.github.com/repos/dolphin-emu/dolphin/subscription', 'commits_url': 'https://api.github.com/repos/dolphin-emu/dolphin/commits{/sha}', 'git_commits_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/commits{/sha}', 'comments_url': 'https://api.github.com/repos/dolphin-emu/dolphin/comments{/number}', 'issue_comment_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/comments{/number}', 'contents_url': 'https://api.github.com/repos/dolphin-emu/dolphin/contents/{+path}', 'compare_url': 'https://api.github.com/repos/dolphin-emu/dolphin/compare/{base}...{head}', 'merges_url': 'https://api.github.com/repos/dolphin-emu/dolphin/merges', 'archive_url': 'https://api.github.com/repos/dolphin-emu/dolphin/{archive_format}{/ref}', 'downloads_url': 'https://api.github.com/repos/dolphin-emu/dolphin/downloads', 'issues_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues{/number}', 'pulls_url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls{/number}', 'milestones_url': 'https://api.github.com/repos/dolphin-emu/dolphin/milestones{/number}', 'notifications_url': 'https://api.github.com/repos/dolphin-emu/dolphin/notifications{?since,all,participating}', 'labels_url': 'https://api.github.com/repos/dolphin-emu/dolphin/labels{/name}', 'releases_url': 'https://api.github.com/repos/dolphin-emu/dolphin/releases{/id}', 'deployments_url': 'https://api.github.com/repos/dolphin-emu/dolphin/deployments', 'created_at': '2013-07-22T09:07:57Z', 'updated_at': '2026-07-18T23:13:54Z', 'pushed_at': '2026-07-18T10:34:54Z', 'git_url': 'git://github.com/dolphin-emu/dolphin.git', 'ssh_url': 'git@github.com:dolphin-emu/dolphin.git', 'clone_url': 'https://github.com/dolphin-emu/dolphin.git', 'svn_url': 'https://github.com/dolphin-emu/dolphin', 'homepage': 'https://dolphin-emu.org', 'size': 558448, 'stargazers_count': 15273, 'watchers_count': 15273, 'language': 'C++', 'has_issues': False, 'has_projects': False, 'has_downloads': True, 'has_wiki': True, 'has_pages': False, 'has_discussions': False, 'forks_count': 3162, 'mirror_url': None, 'archived': False, 'disabled': False, 'open_issues_count': 446, 'license': {'key': 'other', 'name': 'Other', 'spdx_id': 'NOASSERTION', 'url': None, 'node_id': 'MDc6TGljZW5zZTA='}, 'allow_forking': True, 'is_template': False, 'web_commit_signoff_required': False, 'has_pull_requests': True, 'pull_request_creation_policy': 'all', 'topics': ['cpp', 'emulation', 'emulator', 'gamecube', 'wii'], 'visibility': 'public', 'forks': 3162, 'open_issues': 446, 'watchers': 15273, 'default_branch': 'master', 'allow_squash_merge': False, 'allow_merge_commit': True, 'allow_rebase_merge': False, 'allow_auto_merge': False, 'delete_branch_on_merge': False, 'allow_update_branch': False, 'use_squash_pr_title_as_default': False, 'squash_merge_commit_message': 'COMMIT_MESSAGES', 'squash_merge_commit_title': 'COMMIT_OR_PR_TITLE', 'merge_commit_message': 'PR_TITLE', 'merge_commit_title': 'MERGE_MESSAGE'}}, '_links': {'self': {'href': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/14731'}, 'html': {'href': 'https://github.com/dolphin-emu/dolphin/pull/14731'}, 'issue': {'href': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/14731'}, 'comments': {'href': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/14731/comments'}, 'review_comments': {'href': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/14731/comments'}, 'review_comment': {'href': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/comments{/number}'}, 'commits': {'href': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/14731/commits'}, 'statuses': {'href': 'https://api.github.com/repos/dolphin-emu/dolphin/statuses/24b41d58df2315831b74f76b95417f2739d02f9d'}}, 'author_association': 'NONE', 'auto_merge': None, 'assignee': None, 'active_lock_reason': None}, 'repository': {'id': 11577304, 'node_id': 'MDEwOlJlcG9zaXRvcnkxMTU3NzMwNA==', 'name': 'dolphin', 'full_name': 'dolphin-emu/dolphin', 'private': False, 'owner': {'login': 'dolphin-emu', 'id': 5050316, 'node_id': 'MDEyOk9yZ2FuaXphdGlvbjUwNTAzMTY=', 'avatar_url': 'https://avatars.githubusercontent.com/u/5050316?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/dolphin-emu', 'html_url': 'https://github.com/dolphin-emu', 'followers_url': 'https://api.github.com/users/dolphin-emu/followers', 'following_url': 'https://api.github.com/users/dolphin-emu/following{/other_user}', 'gists_url': 'https://api.github.com/users/dolphin-emu/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/dolphin-emu/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/dolphin-emu/subscriptions', 'organizations_url': 'https://api.github.com/users/dolphin-emu/orgs', 'repos_url': 'https://api.github.com/users/dolphin-emu/repos', 'events_url': 'https://api.github.com/users/dolphin-emu/events{/privacy}', 'received_events_url': 'https://api.github.com/users/dolphin-emu/received_events', 'type': 'Organization', 'user_view_type': 'public', 'site_admin': False}, 'html_url': 'https://github.com/dolphin-emu/dolphin', 'description': 'Dolphin is a GameCube / Wii emulator, allowing you to play games for these two platforms on PC with improvements.', 'fork': False, 'url': 'https://api.github.com/repos/dolphin-emu/dolphin', 'forks_url': 'https://api.github.com/repos/dolphin-emu/dolphin/forks', 'keys_url': 'https://api.github.com/repos/dolphin-emu/dolphin/keys{/key_id}', 'collaborators_url': 'https://api.github.com/repos/dolphin-emu/dolphin/collaborators{/collaborator}', 'teams_url': 'https://api.github.com/repos/dolphin-emu/dolphin/teams', 'hooks_url': 'https://api.github.com/repos/dolphin-emu/dolphin/hooks', 'issue_events_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/events{/number}', 'events_url': 'https://api.github.com/repos/dolphin-emu/dolphin/events', 'assignees_url': 'https://api.github.com/repos/dolphin-emu/dolphin/assignees{/user}', 'branches_url': 'https://api.github.com/repos/dolphin-emu/dolphin/branches{/branch}', 'tags_url': 'https://api.github.com/repos/dolphin-emu/dolphin/tags', 'blobs_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/blobs{/sha}', 'git_tags_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/tags{/sha}', 'git_refs_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/refs{/sha}', 'trees_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/trees{/sha}', 'statuses_url': 'https://api.github.com/repos/dolphin-emu/dolphin/statuses/{sha}', 'languages_url': 'https://api.github.com/repos/dolphin-emu/dolphin/languages', 'stargazers_url': 'https://api.github.com/repos/dolphin-emu/dolphin/stargazers', 'contributors_url': 'https://api.github.com/repos/dolphin-emu/dolphin/contributors', 'subscribers_url': 'https://api.github.com/repos/dolphin-emu/dolphin/subscribers', 'subscription_url': 'https://api.github.com/repos/dolphin-emu/dolphin/subscription', 'commits_url': 'https://api.github.com/repos/dolphin-emu/dolphin/commits{/sha}', 'git_commits_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/commits{/sha}', 'comments_url': 'https://api.github.com/repos/dolphin-emu/dolphin/comments{/number}', 'issue_comment_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/comments{/number}', 'contents_url': 'https://api.github.com/repos/dolphin-emu/dolphin/contents/{+path}', 'compare_url': 'https://api.github.com/repos/dolphin-emu/dolphin/compare/{base}...{head}', 'merges_url': 'https://api.github.com/repos/dolphin-emu/dolphin/merges', 'archive_url': 'https://api.github.com/repos/dolphin-emu/dolphin/{archive_format}{/ref}', 'downloads_url': 'https://api.github.com/repos/dolphin-emu/dolphin/downloads', 'issues_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues{/number}', 'pulls_url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls{/number}', 'milestones_url': 'https://api.github.com/repos/dolphin-emu/dolphin/milestones{/number}', 'notifications_url': 'https://api.github.com/repos/dolphin-emu/dolphin/notifications{?since,all,participating}', 'labels_url': 'https://api.github.com/repos/dolphin-emu/dolphin/labels{/name}', 'releases_url': 'https://api.github.com/repos/dolphin-emu/dolphin/releases{/id}', 'deployments_url': 'https://api.github.com/repos/dolphin-emu/dolphin/deployments', 'created_at': '2013-07-22T09:07:57Z', 'updated_at': '2026-07-18T23:13:54Z', 'pushed_at': '2026-07-18T10:34:54Z', 'git_url': 'git://github.com/dolphin-emu/dolphin.git', 'ssh_url': 'git@github.com:dolphin-emu/dolphin.git', 'clone_url': 'https://github.com/dolphin-emu/dolphin.git', 'svn_url': 'https://github.com/dolphin-emu/dolphin', 'homepage': 'https://dolphin-emu.org', 'size': 558448, 'stargazers_count': 15273, 'watchers_count': 15273, 'language': 'C++', 'has_issues': False, 'has_projects': False, 'has_downloads': True, 'has_wiki': True, 'has_pages': False, 'has_discussions': False, 'forks_count': 3162, 'mirror_url': None, 'archived': False, 'disabled': False, 'open_issues_count': 446, 'license': {'key': 'other', 'name': 'Other', 'spdx_id': 'NOASSERTION', 'url': None, 'node_id': 'MDc6TGljZW5zZTA='}, 'allow_forking': True, 'is_template': False, 'web_commit_signoff_required': False, 'has_pull_requests': True, 'pull_request_creation_policy': 'all', 'topics': ['cpp', 'emulation', 'emulator', 'gamecube', 'wii'], 'visibility': 'public', 'forks': 3162, 'open_issues': 446, 'watchers': 15273, 'default_branch': 'master', 'custom_properties': {}}, 'organization': {'login': 'dolphin-emu', 'id': 5050316, 'node_id': 'MDEyOk9yZ2FuaXphdGlvbjUwNTAzMTY=', 'url': 'https://api.github.com/orgs/dolphin-emu', 'repos_url': 'https://api.github.com/orgs/dolphin-emu/repos', 'events_url': 'https://api.github.com/orgs/dolphin-emu/events', 'hooks_url': 'https://api.github.com/orgs/dolphin-emu/hooks', 'issues_url': 'https://api.github.com/orgs/dolphin-emu/issues', 'members_url': 'https://api.github.com/orgs/dolphin-emu/members{/member}', 'public_members_url': 'https://api.github.com/orgs/dolphin-emu/public_members{/member}', 'avatar_url': 'https://avatars.githubusercontent.com/u/5050316?v=4', 'description': ''}, 'sender': {'login': 'thethiny', 'id': 6018214, 'node_id': 'MDQ6VXNlcjYwMTgyMTQ=', 'avatar_url': 'https://avatars.githubusercontent.com/u/6018214?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/thethiny', 'html_url': 'https://github.com/thethiny', 'followers_url': 'https://api.github.com/users/thethiny/followers', 'following_url': 'https://api.github.com/users/thethiny/following{/other_user}', 'gists_url': 'https://api.github.com/users/thethiny/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/thethiny/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/thethiny/subscriptions', 'organizations_url': 'https://api.github.com/users/thethiny/orgs', 'repos_url': 'https://api.github.com/users/thethiny/repos', 'events_url': 'https://api.github.com/users/thethiny/events{/privacy}', 'received_events_url': 'https://api.github.com/users/thethiny/received_events', 'type': 'User', 'user_view_type': 'public', 'site_admin': False}, 'installation': {'id': 35437981, 'node_id': 'MDIzOkludGVncmF0aW9uSW5zdGFsbGF0aW9uMzU0Mzc5ODE='}}, 'type': 'raw_gh_hook'}
2026-07-18T23:29:02.353196	{'source': 'webserver', 'gh_type': 'pull_request_review_comment', 'raw': {'action': 'created', 'comment': {'url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/comments/3609408071', 'pull_request_review_id': 4729491883, 'id': 3609408071, 'node_id': 'PRRC_kwDOALCn2M7XIzJH', 'diff_hunk': '@@ -186,7 +380,304 @@ std::unique_ptr<WbfsFileReader> WbfsFileReader::Create(File::DirectIOFile file,\n   if (!reader->IsGood())\n     reader.reset();\n \n+  if (reader && reader->m_has_nkit_header)\n+    reader->ReadPartitionInfo();\n+\n   return reader;\n }\n \n+// Converts any disc image to WBFS with an NKit v2 header for lossless round-trips.\n+// Strips disc-level junk and partition-level junk (encrypted sectors whose decrypted\n+// content is zero or LFG padding), records a junk bitmap for reconstruction.\n+// See: https://github.com/dolphin-emu/dolphin/pull/14731\n+bool ConvertToWBFS(BlobReader* infile, const std::string& infile_path,\n+                   const std::string& outfile_path, const CompressCB& callback)\n+{\n+  ASSERT(infile->GetDataSizeType() == DataSizeType::Accurate ||\n+         infile->GetDataSizeType() == DataSizeType::UpperBound);\n+\n+  File::DirectIOFile outfile(outfile_path, File::AccessMode::Write);\n+  if (!outfile.IsOpen())\n+  {\n+    PanicAlertFmtT(\n+        "Failed to open the output file \\"{0}\\".\\n"\n+        "Check that you have permissions to write the target folder and that the media can "\n+        "be written.",\n+        outfile_path);\n+    return false;\n+  }\n+\n+  const u64 disc_size = infile->GetDataSize();\n+\n+  // These match the values used by standard WBFS tools (wwt, WBFS Manager)\n+  static constexpr u8 hd_sector_shift = 9;\n+  static constexpr u8 wbfs_sector_shift = 21;\n+  static constexpr u64 hd_sector_size = 1ull << hd_sector_shift;\n+  static constexpr u64 wbfs_sector_size = 1ull << wbfs_sector_shift;\n+\n+  const u64 blocks_per_disc = (disc_size + wbfs_sector_size - 1) / wbfs_sector_size;\n+  const u64 disc_info_size =\n+      Common::AlignUp(WII_DISC_HEADER_SIZE + blocks_per_disc * sizeof(u16), hd_sector_size);\n+\n+  // Read disc header (first 256 bytes contain disc_id, disc_num, title, etc.)\n+  std::vector<u8> disc_header(WII_DISC_HEADER_SIZE, 0);\n+  if (!infile->Read(0, WII_DISC_HEADER_SIZE, disc_header.data()))\n+  {\n+    PanicAlertFmtT("Failed to read from the input file \\"{0}\\".", infile_path);\n+    return false;\n+  }\n+\n+  // Use Volume for partition info and decrypted reads\n+  struct PartitionInfo\n+  {\n+    u64 data_offset;\n+    u64 data_size;\n+    Partition partition;\n+  };\n+  std::vector<PartitionInfo> partitions;\n+\n+  std::unique_ptr<VolumeDisc> volume = CreateDisc(infile_path);\n+  if (volume)\n+  {\n+    for (const Partition& partition : volume->GetPartitions())\n+    {\n+      const std::optional<u64> data_offset =\n+          volume->ReadSwappedAndShifted(partition.offset + 0x2B8, PARTITION_NONE);\n+      const std::optional<u64> data_size =\n+          volume->ReadSwappedAndShifted(partition.offset + 0x2BC, PARTITION_NONE);\n+      if (!data_offset || !data_size)\n+        continue;\n+\n+      PartitionInfo info;\n+      info.data_offset = partition.offset + *data_offset;\n+      info.data_size = *data_size;\n+      info.partition = partition;\n+      partitions.push_back(info);\n+    }\n+  }\n+\n+  // NKit v2 gap type bitmap: 1 bit per block, MSB-first, always sized for dual-layer\n+  const u64 gap_type_blocks = (DL_DVD_SIZE + wbfs_sector_size - 1) / wbfs_sector_size;\n+  const u64 gap_type_bytes = (gap_type_blocks + 7) / 8;\n+  std::vector<u8> gap_type(gap_type_bytes, 0);\n+\n+  // Compute data_start up front so we can write sectors during the scan\n+  const u64 data_start = Common::AlignUp(hd_sector_size + disc_info_size, wbfs_sector_size);\n+  const u16 wlba_base = static_cast<u16>(data_start / wbfs_sector_size);\n+\n+  // Single pass: scan, classify, hash, and write used sectors in one loop\n+  std::vector<u8> sector_buf(wbfs_sector_size, 0);\n+  std::vector<u16> wlba_table(blocks_per_disc, 0);\n+  u16 used_count = 0;\n+\n+  // NKit v2 stores four hash digests for verification\n+  auto sha1_ctx = Common::SHA1::CreateContext();\n+  u32 crc = Common::StartCRC32();\n+  mbedtls_md5_context md5_ctx{};\n+  mbedtls_md5_init(&md5_ctx);\n+  mbedtls_md5_starts_ret(&md5_ctx);\n+  XXH64_state_t* xxh_state = XXH64_createState();\n+  XXH64_reset(xxh_state, 0);\n+\n+  for (u64 i = 0; i < blocks_per_disc; i++)\n+  {\n+    if (i % 100 == 0)\n+    {\n+      const bool was_cancelled =\n+          !callback(Common::GetStringT("Converting"),\n+                    static_cast<float>(i) / static_cast<float>(blocks_per_disc));\n+      if (was_cancelled)\n+      {\n+        XXH64_freeState(xxh_state);\n+        mbedtls_md5_free(&md5_ctx);\n+        outfile.Close();\n+        File::Delete(outfile_path);\n+        return false;\n+      }\n+    }\n+\n+    const u64 offset = i * wbfs_sector_size;\n+    const size_t sz = static_cast<size_t>(std::min(wbfs_sector_size, disc_size - offset));\n+\n+    if (!infile->Read(offset, sz, sector_buf.data()))', 'path': 'Source/Core/DiscIO/WbfsBlob.cpp', 'commit_id': '24b41d58df2315831b74f76b95417f2739d02f9d', 'original_commit_id': '24b41d58df2315831b74f76b95417f2739d02f9d', 'user': {'login': 'thethiny', 'id': 6018214, 'node_id': 'MDQ6VXNlcjYwMTgyMTQ=', 'avatar_url': 'https://avatars.githubusercontent.com/u/6018214?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/thethiny', 'html_url': 'https://github.com/thethiny', 'followers_url': 'https://api.github.com/users/thethiny/followers', 'following_url': 'https://api.github.com/users/thethiny/following{/other_user}', 'gists_url': 'https://api.github.com/users/thethiny/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/thethiny/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/thethiny/subscriptions', 'organizations_url': 'https://api.github.com/users/thethiny/orgs', 'repos_url': 'https://api.github.com/users/thethiny/repos', 'events_url': 'https://api.github.com/users/thethiny/events{/privacy}', 'received_events_url': 'https://api.github.com/users/thethiny/received_events', 'type': 'User', 'user_view_type': 'public', 'site_admin': False}, 'body': 'We can defer the read for classification, but the NKit digests need the raw encrypted bytes for every sector including junk. How should we handle hashing for sectors we skip reading? Should hashing be its own pass separate from this?', 'created_at': '2026-07-18T23:29:00Z', 'updated_at': '2026-07-18T23:29:00Z', 'html_url': 'https://github.com/dolphin-emu/dolphin/pull/14731#discussion_r3609408071', 'pull_request_url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/14731', '_links': {'self': {'href': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/comments/3609408071'}, 'html': {'href': 'https://github.com/dolphin-emu/dolphin/pull/14731#discussion_r3609408071'}, 'pull_request': {'href': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/14731'}}, 'reactions': {'url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/comments/3609408071/reactions', 'total_count': 0, '+1': 0, '-1': 0, 'laugh': 0, 'hooray': 0, 'confused': 0, 'heart': 0, 'rocket': 0, 'eyes': 0}, 'start_line': None, 'original_start_line': None, 'start_side': None, 'line': 502, 'original_line': 502, 'side': 'RIGHT', 'in_reply_to_id': 3609251889, 'author_association': 'NONE', 'original_position': 409, 'position': 409, 'subject_type': 'line'}, 'pull_request': {'url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/14731', 'id': 4056977334, 'node_id': 'PR_kwDOALCn2M7x0I-2', 'html_url': 'https://github.com/dolphin-emu/dolphin/pull/14731', 'diff_url': 'https://github.com/dolphin-emu/dolphin/pull/14731.diff', 'patch_url': 'https://github.com/dolphin-emu/dolphin/pull/14731.patch', 'issue_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/14731', 'number': 14731, 'state': 'open', 'locked': False, 'title': 'Convert To WBFS Support', 'user': {'login': 'thethiny', 'id': 6018214, 'node_id': 'MDQ6VXNlcjYwMTgyMTQ=', 'avatar_url': 'https://avatars.githubusercontent.com/u/6018214?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/thethiny', 'html_url': 'https://github.com/thethiny', 'followers_url': 'https://api.github.com/users/thethiny/followers', 'following_url': 'https://api.github.com/users/thethiny/following{/other_user}', 'gists_url': 'https://api.github.com/users/thethiny/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/thethiny/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/thethiny/subscriptions', 'organizations_url': 'https://api.github.com/users/thethiny/orgs', 'repos_url': 'https://api.github.com/users/thethiny/repos', 'events_url': 'https://api.github.com/users/thethiny/events{/privacy}', 'received_events_url': 'https://api.github.com/users/thethiny/received_events', 'type': 'User', 'user_view_type': 'public', 'site_admin': False}, 'body': "This PR introduces Conversion **to** WBFS support. WBFS is the format that is used by USB Loaders on a real Wii device.\r\n\r\n## Design decisions & hardcoded values\r\nThe writer uses fixed sector sizes that match what [libwbfs (the reference implementation by kwiirk)](https://github.com/kwiirk/wbfs/blob/master/libwbfs/libwbfs.c#L128-L134) computes for a standard single-layer Wii disc. These 2 hardcodes are stable and work correctly across all my testings.\r\n- HD sector shift: 9 (512 bytes)\r\n- WBFS sector shift: 21 (2 MiB)\r\nThese are not configurable via the UI. All existing WBFS tools use these values, and since the aim is to support USB Loaders then this has been tested and it is working on a real Wii.\r\n\r\nConverting from WBFS is not enabled. The existing `WbfsFileReader` reports `DataSizeType::UpperBound`, and `ShouldAllowConversion()` requires `Accurate`. I am able to support this but since it was hardcoded by the Dolphin team I thought a discussion is warranted.\r\n\r\n## Testing\r\n- Verified with DolphinTool header and DolphinTool verify\r\n- Verified with wit FILETYPE and wit DUMP (Wiimm's ISO Tools recognizes valid WBFS structure, partitions, encryption)\r\n- Tested ISO to WBFS and RVZ to WBFS conversions\r\n- Output file sizes match Wii Backup Manager when scrubbing is enabled (~0.1% difference), works when scrubbing is disabled.\r\n- Output WBFS files play correctly in Dolphin\r\n- Output WBFS files play correctly on a real Wii using USB Loader GX e25c4f3\r\n", 'created_at': '2026-07-15T01:16:25Z', 'updated_at': '2026-07-18T23:14:45Z', 'closed_at': None, 'merged_at': None, 'merge_commit_sha': '228f93416dd80eb09da834ad7852c8eaa4d9212b', 'assignees': [], 'requested_reviewers': [], 'requested_teams': [], 'labels': [], 'milestone': None, 'draft': False, 'commits_url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/14731/commits', 'review_comments_url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/14731/comments', 'review_comment_url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/comments{/number}', 'comments_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/14731/comments', 'statuses_url': 'https://api.github.com/repos/dolphin-emu/dolphin/statuses/24b41d58df2315831b74f76b95417f2739d02f9d', 'head': {'label': 'thethiny:wbfs-conversion', 'ref': 'wbfs-conversion', 'sha': '24b41d58df2315831b74f76b95417f2739d02f9d', 'user': {'login': 'thethiny', 'id': 6018214, 'node_id': 'MDQ6VXNlcjYwMTgyMTQ=', 'avatar_url': 'https://avatars.githubusercontent.com/u/6018214?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/thethiny', 'html_url': 'https://github.com/thethiny', 'followers_url': 'https://api.github.com/users/thethiny/followers', 'following_url': 'https://api.github.com/users/thethiny/following{/other_user}', 'gists_url': 'https://api.github.com/users/thethiny/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/thethiny/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/thethiny/subscriptions', 'organizations_url': 'https://api.github.com/users/thethiny/orgs', 'repos_url': 'https://api.github.com/users/thethiny/repos', 'events_url': 'https://api.github.com/users/thethiny/events{/privacy}', 'received_events_url': 'https://api.github.com/users/thethiny/received_events', 'type': 'User', 'user_view_type': 'public', 'site_admin': False}, 'repo': {'id': 1298654395, 'node_id': 'R_kgDOTWfkuw', 'name': 'dolphin', 'full_name': 'thethiny/dolphin', 'private': False, 'owner': {'login': 'thethiny', 'id': 6018214, 'node_id': 'MDQ6VXNlcjYwMTgyMTQ=', 'avatar_url': 'https://avatars.githubusercontent.com/u/6018214?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/thethiny', 'html_url': 'https://github.com/thethiny', 'followers_url': 'https://api.github.com/users/thethiny/followers', 'following_url': 'https://api.github.com/users/thethiny/following{/other_user}', 'gists_url': 'https://api.github.com/users/thethiny/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/thethiny/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/thethiny/subscriptions', 'organizations_url': 'https://api.github.com/users/thethiny/orgs', 'repos_url': 'https://api.github.com/users/thethiny/repos', 'events_url': 'https://api.github.com/users/thethiny/events{/privacy}', 'received_events_url': 'https://api.github.com/users/thethiny/received_events', 'type': 'User', 'user_view_type': 'public', 'site_admin': False}, 'html_url': 'https://github.com/thethiny/dolphin', 'description': 'Dolphin is a GameCube / Wii emulator, allowing you to play games for these two platforms on PC with improvements.', 'fork': True, 'url': 'https://api.github.com/repos/thethiny/dolphin', 'forks_url': 'https://api.github.com/repos/thethiny/dolphin/forks', 'keys_url': 'https://api.github.com/repos/thethiny/dolphin/keys{/key_id}', 'collaborators_url': 'https://api.github.com/repos/thethiny/dolphin/collaborators{/collaborator}', 'teams_url': 'https://api.github.com/repos/thethiny/dolphin/teams', 'hooks_url': 'https://api.github.com/repos/thethiny/dolphin/hooks', 'issue_events_url': 'https://api.github.com/repos/thethiny/dolphin/issues/events{/number}', 'events_url': 'https://api.github.com/repos/thethiny/dolphin/events', 'assignees_url': 'https://api.github.com/repos/thethiny/dolphin/assignees{/user}', 'branches_url': 'https://api.github.com/repos/thethiny/dolphin/branches{/branch}', 'tags_url': 'https://api.github.com/repos/thethiny/dolphin/tags', 'blobs_url': 'https://api.github.com/repos/thethiny/dolphin/git/blobs{/sha}', 'git_tags_url': 'https://api.github.com/repos/thethiny/dolphin/git/tags{/sha}', 'git_refs_url': 'https://api.github.com/repos/thethiny/dolphin/git/refs{/sha}', 'trees_url': 'https://api.github.com/repos/thethiny/dolphin/git/trees{/sha}', 'statuses_url': 'https://api.github.com/repos/thethiny/dolphin/statuses/{sha}', 'languages_url': 'https://api.github.com/repos/thethiny/dolphin/languages', 'stargazers_url': 'https://api.github.com/repos/thethiny/dolphin/stargazers', 'contributors_url': 'https://api.github.com/repos/thethiny/dolphin/contributors', 'subscribers_url': 'https://api.github.com/repos/thethiny/dolphin/subscribers', 'subscription_url': 'https://api.github.com/repos/thethiny/dolphin/subscription', 'commits_url': 'https://api.github.com/repos/thethiny/dolphin/commits{/sha}', 'git_commits_url': 'https://api.github.com/repos/thethiny/dolphin/git/commits{/sha}', 'comments_url': 'https://api.github.com/repos/thethiny/dolphin/comments{/number}', 'issue_comment_url': 'https://api.github.com/repos/thethiny/dolphin/issues/comments{/number}', 'contents_url': 'https://api.github.com/repos/thethiny/dolphin/contents/{+path}', 'compare_url': 'https://api.github.com/repos/thethiny/dolphin/compare/{base}...{head}', 'merges_url': 'https://api.github.com/repos/thethiny/dolphin/merges', 'archive_url': 'https://api.github.com/repos/thethiny/dolphin/{archive_format}{/ref}', 'downloads_url': 'https://api.github.com/repos/thethiny/dolphin/downloads', 'issues_url': 'https://api.github.com/repos/thethiny/dolphin/issues{/number}', 'pulls_url': 'https://api.github.com/repos/thethiny/dolphin/pulls{/number}', 'milestones_url': 'https://api.github.com/repos/thethiny/dolphin/milestones{/number}', 'notifications_url': 'https://api.github.com/repos/thethiny/dolphin/notifications{?since,all,participating}', 'labels_url': 'https://api.github.com/repos/thethiny/dolphin/labels{/name}', 'releases_url': 'https://api.github.com/repos/thethiny/dolphin/releases{/id}', 'deployments_url': 'https://api.github.com/repos/thethiny/dolphin/deployments', 'created_at': '2026-07-12T22:09:13Z', 'updated_at': '2026-07-12T22:09:13Z', 'pushed_at': '2026-07-18T20:35:03Z', 'git_url': 'git://github.com/thethiny/dolphin.git', 'ssh_url': 'git@github.com:thethiny/dolphin.git', 'clone_url': 'https://github.com/thethiny/dolphin.git', 'svn_url': 'https://github.com/thethiny/dolphin', 'homepage': 'https://dolphin-emu.org', 'size': 515471, 'stargazers_count': 0, 'watchers_count': 0, 'language': None, 'has_issues': False, 'has_projects': True, 'has_downloads': True, 'has_wiki': True, 'has_pages': False, 'has_discussions': False, 'forks_count': 0, 'mirror_url': None, 'archived': False, 'disabled': False, 'open_issues_count': 0, 'license': {'key': 'other', 'name': 'Other', 'spdx_id': 'NOASSERTION', 'url': None, 'node_id': 'MDc6TGljZW5zZTA='}, 'allow_forking': True, 'is_template': False, 'web_commit_signoff_required': False, 'has_pull_requests': True, 'pull_request_creation_policy': 'all', 'topics': [], 'visibility': 'public', 'forks': 0, 'open_issues': 0, 'watchers': 0, 'default_branch': 'master', 'allow_squash_merge': True, 'allow_merge_commit': True, 'allow_rebase_merge': True, 'allow_auto_merge': False, 'delete_branch_on_merge': False, 'allow_update_branch': False, 'use_squash_pr_title_as_default': False, 'squash_merge_commit_message': 'COMMIT_MESSAGES', 'squash_merge_commit_title': 'COMMIT_OR_PR_TITLE', 'merge_commit_message': 'PR_TITLE', 'merge_commit_title': 'MERGE_MESSAGE'}}, 'base': {'label': 'dolphin-emu:master', 'ref': 'master', 'sha': 'd3b2943807dd0073f7767947466dd73cccfef319', 'user': {'login': 'dolphin-emu', 'id': 5050316, 'node_id': 'MDEyOk9yZ2FuaXphdGlvbjUwNTAzMTY=', 'avatar_url': 'https://avatars.githubusercontent.com/u/5050316?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/dolphin-emu', 'html_url': 'https://github.com/dolphin-emu', 'followers_url': 'https://api.github.com/users/dolphin-emu/followers', 'following_url': 'https://api.github.com/users/dolphin-emu/following{/other_user}', 'gists_url': 'https://api.github.com/users/dolphin-emu/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/dolphin-emu/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/dolphin-emu/subscriptions', 'organizations_url': 'https://api.github.com/users/dolphin-emu/orgs', 'repos_url': 'https://api.github.com/users/dolphin-emu/repos', 'events_url': 'https://api.github.com/users/dolphin-emu/events{/privacy}', 'received_events_url': 'https://api.github.com/users/dolphin-emu/received_events', 'type': 'Organization', 'user_view_type': 'public', 'site_admin': False}, 'repo': {'id': 11577304, 'node_id': 'MDEwOlJlcG9zaXRvcnkxMTU3NzMwNA==', 'name': 'dolphin', 'full_name': 'dolphin-emu/dolphin', 'private': False, 'owner': {'login': 'dolphin-emu', 'id': 5050316, 'node_id': 'MDEyOk9yZ2FuaXphdGlvbjUwNTAzMTY=', 'avatar_url': 'https://avatars.githubusercontent.com/u/5050316?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/dolphin-emu', 'html_url': 'https://github.com/dolphin-emu', 'followers_url': 'https://api.github.com/users/dolphin-emu/followers', 'following_url': 'https://api.github.com/users/dolphin-emu/following{/other_user}', 'gists_url': 'https://api.github.com/users/dolphin-emu/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/dolphin-emu/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/dolphin-emu/subscriptions', 'organizations_url': 'https://api.github.com/users/dolphin-emu/orgs', 'repos_url': 'https://api.github.com/users/dolphin-emu/repos', 'events_url': 'https://api.github.com/users/dolphin-emu/events{/privacy}', 'received_events_url': 'https://api.github.com/users/dolphin-emu/received_events', 'type': 'Organization', 'user_view_type': 'public', 'site_admin': False}, 'html_url': 'https://github.com/dolphin-emu/dolphin', 'description': 'Dolphin is a GameCube / Wii emulator, allowing you to play games for these two platforms on PC with improvements.', 'fork': False, 'url': 'https://api.github.com/repos/dolphin-emu/dolphin', 'forks_url': 'https://api.github.com/repos/dolphin-emu/dolphin/forks', 'keys_url': 'https://api.github.com/repos/dolphin-emu/dolphin/keys{/key_id}', 'collaborators_url': 'https://api.github.com/repos/dolphin-emu/dolphin/collaborators{/collaborator}', 'teams_url': 'https://api.github.com/repos/dolphin-emu/dolphin/teams', 'hooks_url': 'https://api.github.com/repos/dolphin-emu/dolphin/hooks', 'issue_events_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/events{/number}', 'events_url': 'https://api.github.com/repos/dolphin-emu/dolphin/events', 'assignees_url': 'https://api.github.com/repos/dolphin-emu/dolphin/assignees{/user}', 'branches_url': 'https://api.github.com/repos/dolphin-emu/dolphin/branches{/branch}', 'tags_url': 'https://api.github.com/repos/dolphin-emu/dolphin/tags', 'blobs_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/blobs{/sha}', 'git_tags_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/tags{/sha}', 'git_refs_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/refs{/sha}', 'trees_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/trees{/sha}', 'statuses_url': 'https://api.github.com/repos/dolphin-emu/dolphin/statuses/{sha}', 'languages_url': 'https://api.github.com/repos/dolphin-emu/dolphin/languages', 'stargazers_url': 'https://api.github.com/repos/dolphin-emu/dolphin/stargazers', 'contributors_url': 'https://api.github.com/repos/dolphin-emu/dolphin/contributors', 'subscribers_url': 'https://api.github.com/repos/dolphin-emu/dolphin/subscribers', 'subscription_url': 'https://api.github.com/repos/dolphin-emu/dolphin/subscription', 'commits_url': 'https://api.github.com/repos/dolphin-emu/dolphin/commits{/sha}', 'git_commits_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/commits{/sha}', 'comments_url': 'https://api.github.com/repos/dolphin-emu/dolphin/comments{/number}', 'issue_comment_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/comments{/number}', 'contents_url': 'https://api.github.com/repos/dolphin-emu/dolphin/contents/{+path}', 'compare_url': 'https://api.github.com/repos/dolphin-emu/dolphin/compare/{base}...{head}', 'merges_url': 'https://api.github.com/repos/dolphin-emu/dolphin/merges', 'archive_url': 'https://api.github.com/repos/dolphin-emu/dolphin/{archive_format}{/ref}', 'downloads_url': 'https://api.github.com/repos/dolphin-emu/dolphin/downloads', 'issues_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues{/number}', 'pulls_url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls{/number}', 'milestones_url': 'https://api.github.com/repos/dolphin-emu/dolphin/milestones{/number}', 'notifications_url': 'https://api.github.com/repos/dolphin-emu/dolphin/notifications{?since,all,participating}', 'labels_url': 'https://api.github.com/repos/dolphin-emu/dolphin/labels{/name}', 'releases_url': 'https://api.github.com/repos/dolphin-emu/dolphin/releases{/id}', 'deployments_url': 'https://api.github.com/repos/dolphin-emu/dolphin/deployments', 'created_at': '2013-07-22T09:07:57Z', 'updated_at': '2026-07-18T23:13:54Z', 'pushed_at': '2026-07-18T10:34:54Z', 'git_url': 'git://github.com/dolphin-emu/dolphin.git', 'ssh_url': 'git@github.com:dolphin-emu/dolphin.git', 'clone_url': 'https://github.com/dolphin-emu/dolphin.git', 'svn_url': 'https://github.com/dolphin-emu/dolphin', 'homepage': 'https://dolphin-emu.org', 'size': 558448, 'stargazers_count': 15273, 'watchers_count': 15273, 'language': 'C++', 'has_issues': False, 'has_projects': False, 'has_downloads': True, 'has_wiki': True, 'has_pages': False, 'has_discussions': False, 'forks_count': 3162, 'mirror_url': None, 'archived': False, 'disabled': False, 'open_issues_count': 446, 'license': {'key': 'other', 'name': 'Other', 'spdx_id': 'NOASSERTION', 'url': None, 'node_id': 'MDc6TGljZW5zZTA='}, 'allow_forking': True, 'is_template': False, 'web_commit_signoff_required': False, 'has_pull_requests': True, 'pull_request_creation_policy': 'all', 'topics': ['cpp', 'emulation', 'emulator', 'gamecube', 'wii'], 'visibility': 'public', 'forks': 3162, 'open_issues': 446, 'watchers': 15273, 'default_branch': 'master', 'allow_squash_merge': False, 'allow_merge_commit': True, 'allow_rebase_merge': False, 'allow_auto_merge': False, 'delete_branch_on_merge': False, 'allow_update_branch': False, 'use_squash_pr_title_as_default': False, 'squash_merge_commit_message': 'COMMIT_MESSAGES', 'squash_merge_commit_title': 'COMMIT_OR_PR_TITLE', 'merge_commit_message': 'PR_TITLE', 'merge_commit_title': 'MERGE_MESSAGE'}}, '_links': {'self': {'href': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/14731'}, 'html': {'href': 'https://github.com/dolphin-emu/dolphin/pull/14731'}, 'issue': {'href': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/14731'}, 'comments': {'href': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/14731/comments'}, 'review_comments': {'href': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/14731/comments'}, 'review_comment': {'href': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/comments{/number}'}, 'commits': {'href': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/14731/commits'}, 'statuses': {'href': 'https://api.github.com/repos/dolphin-emu/dolphin/statuses/24b41d58df2315831b74f76b95417f2739d02f9d'}}, 'author_association': 'NONE', 'auto_merge': None, 'assignee': None, 'active_lock_reason': None}, 'repository': {'id': 11577304, 'node_id': 'MDEwOlJlcG9zaXRvcnkxMTU3NzMwNA==', 'name': 'dolphin', 'full_name': 'dolphin-emu/dolphin', 'private': False, 'owner': {'login': 'dolphin-emu', 'id': 5050316, 'node_id': 'MDEyOk9yZ2FuaXphdGlvbjUwNTAzMTY=', 'avatar_url': 'https://avatars.githubusercontent.com/u/5050316?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/dolphin-emu', 'html_url': 'https://github.com/dolphin-emu', 'followers_url': 'https://api.github.com/users/dolphin-emu/followers', 'following_url': 'https://api.github.com/users/dolphin-emu/following{/other_user}', 'gists_url': 'https://api.github.com/users/dolphin-emu/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/dolphin-emu/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/dolphin-emu/subscriptions', 'organizations_url': 'https://api.github.com/users/dolphin-emu/orgs', 'repos_url': 'https://api.github.com/users/dolphin-emu/repos', 'events_url': 'https://api.github.com/users/dolphin-emu/events{/privacy}', 'received_events_url': 'https://api.github.com/users/dolphin-emu/received_events', 'type': 'Organization', 'user_view_type': 'public', 'site_admin': False}, 'html_url': 'https://github.com/dolphin-emu/dolphin', 'description': 'Dolphin is a GameCube / Wii emulator, allowing you to play games for these two platforms on PC with improvements.', 'fork': False, 'url': 'https://api.github.com/repos/dolphin-emu/dolphin', 'forks_url': 'https://api.github.com/repos/dolphin-emu/dolphin/forks', 'keys_url': 'https://api.github.com/repos/dolphin-emu/dolphin/keys{/key_id}', 'collaborators_url': 'https://api.github.com/repos/dolphin-emu/dolphin/collaborators{/collaborator}', 'teams_url': 'https://api.github.com/repos/dolphin-emu/dolphin/teams', 'hooks_url': 'https://api.github.com/repos/dolphin-emu/dolphin/hooks', 'issue_events_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/events{/number}', 'events_url': 'https://api.github.com/repos/dolphin-emu/dolphin/events', 'assignees_url': 'https://api.github.com/repos/dolphin-emu/dolphin/assignees{/user}', 'branches_url': 'https://api.github.com/repos/dolphin-emu/dolphin/branches{/branch}', 'tags_url': 'https://api.github.com/repos/dolphin-emu/dolphin/tags', 'blobs_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/blobs{/sha}', 'git_tags_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/tags{/sha}', 'git_refs_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/refs{/sha}', 'trees_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/trees{/sha}', 'statuses_url': 'https://api.github.com/repos/dolphin-emu/dolphin/statuses/{sha}', 'languages_url': 'https://api.github.com/repos/dolphin-emu/dolphin/languages', 'stargazers_url': 'https://api.github.com/repos/dolphin-emu/dolphin/stargazers', 'contributors_url': 'https://api.github.com/repos/dolphin-emu/dolphin/contributors', 'subscribers_url': 'https://api.github.com/repos/dolphin-emu/dolphin/subscribers', 'subscription_url': 'https://api.github.com/repos/dolphin-emu/dolphin/subscription', 'commits_url': 'https://api.github.com/repos/dolphin-emu/dolphin/commits{/sha}', 'git_commits_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/commits{/sha}', 'comments_url': 'https://api.github.com/repos/dolphin-emu/dolphin/comments{/number}', 'issue_comment_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/comments{/number}', 'contents_url': 'https://api.github.com/repos/dolphin-emu/dolphin/contents/{+path}', 'compare_url': 'https://api.github.com/repos/dolphin-emu/dolphin/compare/{base}...{head}', 'merges_url': 'https://api.github.com/repos/dolphin-emu/dolphin/merges', 'archive_url': 'https://api.github.com/repos/dolphin-emu/dolphin/{archive_format}{/ref}', 'downloads_url': 'https://api.github.com/repos/dolphin-emu/dolphin/downloads', 'issues_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues{/number}', 'pulls_url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls{/number}', 'milestones_url': 'https://api.github.com/repos/dolphin-emu/dolphin/milestones{/number}', 'notifications_url': 'https://api.github.com/repos/dolphin-emu/dolphin/notifications{?since,all,participating}', 'labels_url': 'https://api.github.com/repos/dolphin-emu/dolphin/labels{/name}', 'releases_url': 'https://api.github.com/repos/dolphin-emu/dolphin/releases{/id}', 'deployments_url': 'https://api.github.com/repos/dolphin-emu/dolphin/deployments', 'created_at': '2013-07-22T09:07:57Z', 'updated_at': '2026-07-18T23:13:54Z', 'pushed_at': '2026-07-18T10:34:54Z', 'git_url': 'git://github.com/dolphin-emu/dolphin.git', 'ssh_url': 'git@github.com:dolphin-emu/dolphin.git', 'clone_url': 'https://github.com/dolphin-emu/dolphin.git', 'svn_url': 'https://github.com/dolphin-emu/dolphin', 'homepage': 'https://dolphin-emu.org', 'size': 558448, 'stargazers_count': 15273, 'watchers_count': 15273, 'language': 'C++', 'has_issues': False, 'has_projects': False, 'has_downloads': True, 'has_wiki': True, 'has_pages': False, 'has_discussions': False, 'forks_count': 3162, 'mirror_url': None, 'archived': False, 'disabled': False, 'open_issues_count': 446, 'license': {'key': 'other', 'name': 'Other', 'spdx_id': 'NOASSERTION', 'url': None, 'node_id': 'MDc6TGljZW5zZTA='}, 'allow_forking': True, 'is_template': False, 'web_commit_signoff_required': False, 'has_pull_requests': True, 'pull_request_creation_policy': 'all', 'topics': ['cpp', 'emulation', 'emulator', 'gamecube', 'wii'], 'visibility': 'public', 'forks': 3162, 'open_issues': 446, 'watchers': 15273, 'default_branch': 'master', 'custom_properties': {}}, 'organization': {'login': 'dolphin-emu', 'id': 5050316, 'node_id': 'MDEyOk9yZ2FuaXphdGlvbjUwNTAzMTY=', 'url': 'https://api.github.com/orgs/dolphin-emu', 'repos_url': 'https://api.github.com/orgs/dolphin-emu/repos', 'events_url': 'https://api.github.com/orgs/dolphin-emu/events', 'hooks_url': 'https://api.github.com/orgs/dolphin-emu/hooks', 'issues_url': 'https://api.github.com/orgs/dolphin-emu/issues', 'members_url': 'https://api.github.com/orgs/dolphin-emu/members{/member}', 'public_members_url': 'https://api.github.com/orgs/dolphin-emu/public_members{/member}', 'avatar_url': 'https://avatars.githubusercontent.com/u/5050316?v=4', 'description': ''}, 'sender': {'login': 'thethiny', 'id': 6018214, 'node_id': 'MDQ6VXNlcjYwMTgyMTQ=', 'avatar_url': 'https://avatars.githubusercontent.com/u/6018214?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/thethiny', 'html_url': 'https://github.com/thethiny', 'followers_url': 'https://api.github.com/users/thethiny/followers', 'following_url': 'https://api.github.com/users/thethiny/following{/other_user}', 'gists_url': 'https://api.github.com/users/thethiny/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/thethiny/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/thethiny/subscriptions', 'organizations_url': 'https://api.github.com/users/thethiny/orgs', 'repos_url': 'https://api.github.com/users/thethiny/repos', 'events_url': 'https://api.github.com/users/thethiny/events{/privacy}', 'received_events_url': 'https://api.github.com/users/thethiny/received_events', 'type': 'User', 'user_view_type': 'public', 'site_admin': False}, 'installation': {'id': 35437981, 'node_id': 'MDIzOkludGVncmF0aW9uSW5zdGFsbGF0aW9uMzU0Mzc5ODE='}}, 'type': 'raw_gh_hook'}
2026-07-18T23:29:02.352482	{'source': 'webserver', 'gh_type': 'pull_request_review', 'raw': {'action': 'submitted', 'review': {'id': 4729491883, 'node_id': 'PRR_kwDOALCn2M8AAAABGeZRqw', 'user': {'login': 'thethiny', 'id': 6018214, 'node_id': 'MDQ6VXNlcjYwMTgyMTQ=', 'avatar_url': 'https://avatars.githubusercontent.com/u/6018214?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/thethiny', 'html_url': 'https://github.com/thethiny', 'followers_url': 'https://api.github.com/users/thethiny/followers', 'following_url': 'https://api.github.com/users/thethiny/following{/other_user}', 'gists_url': 'https://api.github.com/users/thethiny/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/thethiny/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/thethiny/subscriptions', 'organizations_url': 'https://api.github.com/users/thethiny/orgs', 'repos_url': 'https://api.github.com/users/thethiny/repos', 'events_url': 'https://api.github.com/users/thethiny/events{/privacy}', 'received_events_url': 'https://api.github.com/users/thethiny/received_events', 'type': 'User', 'user_view_type': 'public', 'site_admin': False}, 'body': None, 'commit_id': '24b41d58df2315831b74f76b95417f2739d02f9d', 'state': 'commented', 'html_url': 'https://github.com/dolphin-emu/dolphin/pull/14731#pullrequestreview-4729491883', 'pull_request_url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/14731', '_links': {'html': {'href': 'https://github.com/dolphin-emu/dolphin/pull/14731#pullrequestreview-4729491883'}, 'pull_request': {'href': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/14731'}}, 'submitted_at': '2026-07-18T23:29:00Z', 'updated_at': '2026-07-18T23:29:00Z', 'author_association': 'NONE'}, 'pull_request': {'url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/14731', 'id': 4056977334, 'node_id': 'PR_kwDOALCn2M7x0I-2', 'html_url': 'https://github.com/dolphin-emu/dolphin/pull/14731', 'diff_url': 'https://github.com/dolphin-emu/dolphin/pull/14731.diff', 'patch_url': 'https://github.com/dolphin-emu/dolphin/pull/14731.patch', 'issue_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/14731', 'number': 14731, 'state': 'open', 'locked': False, 'title': 'Convert To WBFS Support', 'user': {'login': 'thethiny', 'id': 6018214, 'node_id': 'MDQ6VXNlcjYwMTgyMTQ=', 'avatar_url': 'https://avatars.githubusercontent.com/u/6018214?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/thethiny', 'html_url': 'https://github.com/thethiny', 'followers_url': 'https://api.github.com/users/thethiny/followers', 'following_url': 'https://api.github.com/users/thethiny/following{/other_user}', 'gists_url': 'https://api.github.com/users/thethiny/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/thethiny/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/thethiny/subscriptions', 'organizations_url': 'https://api.github.com/users/thethiny/orgs', 'repos_url': 'https://api.github.com/users/thethiny/repos', 'events_url': 'https://api.github.com/users/thethiny/events{/privacy}', 'received_events_url': 'https://api.github.com/users/thethiny/received_events', 'type': 'User', 'user_view_type': 'public', 'site_admin': False}, 'body': "This PR introduces Conversion **to** WBFS support. WBFS is the format that is used by USB Loaders on a real Wii device.\r\n\r\n## Design decisions & hardcoded values\r\nThe writer uses fixed sector sizes that match what [libwbfs (the reference implementation by kwiirk)](https://github.com/kwiirk/wbfs/blob/master/libwbfs/libwbfs.c#L128-L134) computes for a standard single-layer Wii disc. These 2 hardcodes are stable and work correctly across all my testings.\r\n- HD sector shift: 9 (512 bytes)\r\n- WBFS sector shift: 21 (2 MiB)\r\nThese are not configurable via the UI. All existing WBFS tools use these values, and since the aim is to support USB Loaders then this has been tested and it is working on a real Wii.\r\n\r\nConverting from WBFS is not enabled. The existing `WbfsFileReader` reports `DataSizeType::UpperBound`, and `ShouldAllowConversion()` requires `Accurate`. I am able to support this but since it was hardcoded by the Dolphin team I thought a discussion is warranted.\r\n\r\n## Testing\r\n- Verified with DolphinTool header and DolphinTool verify\r\n- Verified with wit FILETYPE and wit DUMP (Wiimm's ISO Tools recognizes valid WBFS structure, partitions, encryption)\r\n- Tested ISO to WBFS and RVZ to WBFS conversions\r\n- Output file sizes match Wii Backup Manager when scrubbing is enabled (~0.1% difference), works when scrubbing is disabled.\r\n- Output WBFS files play correctly in Dolphin\r\n- Output WBFS files play correctly on a real Wii using USB Loader GX e25c4f3\r\n", 'created_at': '2026-07-15T01:16:25Z', 'updated_at': '2026-07-18T23:14:45Z', 'closed_at': None, 'merged_at': None, 'merge_commit_sha': '228f93416dd80eb09da834ad7852c8eaa4d9212b', 'assignees': [], 'requested_reviewers': [], 'requested_teams': [], 'labels': [], 'milestone': None, 'draft': False, 'commits_url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/14731/commits', 'review_comments_url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/14731/comments', 'review_comment_url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/comments{/number}', 'comments_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/14731/comments', 'statuses_url': 'https://api.github.com/repos/dolphin-emu/dolphin/statuses/24b41d58df2315831b74f76b95417f2739d02f9d', 'head': {'label': 'thethiny:wbfs-conversion', 'ref': 'wbfs-conversion', 'sha': '24b41d58df2315831b74f76b95417f2739d02f9d', 'user': {'login': 'thethiny', 'id': 6018214, 'node_id': 'MDQ6VXNlcjYwMTgyMTQ=', 'avatar_url': 'https://avatars.githubusercontent.com/u/6018214?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/thethiny', 'html_url': 'https://github.com/thethiny', 'followers_url': 'https://api.github.com/users/thethiny/followers', 'following_url': 'https://api.github.com/users/thethiny/following{/other_user}', 'gists_url': 'https://api.github.com/users/thethiny/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/thethiny/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/thethiny/subscriptions', 'organizations_url': 'https://api.github.com/users/thethiny/orgs', 'repos_url': 'https://api.github.com/users/thethiny/repos', 'events_url': 'https://api.github.com/users/thethiny/events{/privacy}', 'received_events_url': 'https://api.github.com/users/thethiny/received_events', 'type': 'User', 'user_view_type': 'public', 'site_admin': False}, 'repo': {'id': 1298654395, 'node_id': 'R_kgDOTWfkuw', 'name': 'dolphin', 'full_name': 'thethiny/dolphin', 'private': False, 'owner': {'login': 'thethiny', 'id': 6018214, 'node_id': 'MDQ6VXNlcjYwMTgyMTQ=', 'avatar_url': 'https://avatars.githubusercontent.com/u/6018214?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/thethiny', 'html_url': 'https://github.com/thethiny', 'followers_url': 'https://api.github.com/users/thethiny/followers', 'following_url': 'https://api.github.com/users/thethiny/following{/other_user}', 'gists_url': 'https://api.github.com/users/thethiny/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/thethiny/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/thethiny/subscriptions', 'organizations_url': 'https://api.github.com/users/thethiny/orgs', 'repos_url': 'https://api.github.com/users/thethiny/repos', 'events_url': 'https://api.github.com/users/thethiny/events{/privacy}', 'received_events_url': 'https://api.github.com/users/thethiny/received_events', 'type': 'User', 'user_view_type': 'public', 'site_admin': False}, 'html_url': 'https://github.com/thethiny/dolphin', 'description': 'Dolphin is a GameCube / Wii emulator, allowing you to play games for these two platforms on PC with improvements.', 'fork': True, 'url': 'https://api.github.com/repos/thethiny/dolphin', 'forks_url': 'https://api.github.com/repos/thethiny/dolphin/forks', 'keys_url': 'https://api.github.com/repos/thethiny/dolphin/keys{/key_id}', 'collaborators_url': 'https://api.github.com/repos/thethiny/dolphin/collaborators{/collaborator}', 'teams_url': 'https://api.github.com/repos/thethiny/dolphin/teams', 'hooks_url': 'https://api.github.com/repos/thethiny/dolphin/hooks', 'issue_events_url': 'https://api.github.com/repos/thethiny/dolphin/issues/events{/number}', 'events_url': 'https://api.github.com/repos/thethiny/dolphin/events', 'assignees_url': 'https://api.github.com/repos/thethiny/dolphin/assignees{/user}', 'branches_url': 'https://api.github.com/repos/thethiny/dolphin/branches{/branch}', 'tags_url': 'https://api.github.com/repos/thethiny/dolphin/tags', 'blobs_url': 'https://api.github.com/repos/thethiny/dolphin/git/blobs{/sha}', 'git_tags_url': 'https://api.github.com/repos/thethiny/dolphin/git/tags{/sha}', 'git_refs_url': 'https://api.github.com/repos/thethiny/dolphin/git/refs{/sha}', 'trees_url': 'https://api.github.com/repos/thethiny/dolphin/git/trees{/sha}', 'statuses_url': 'https://api.github.com/repos/thethiny/dolphin/statuses/{sha}', 'languages_url': 'https://api.github.com/repos/thethiny/dolphin/languages', 'stargazers_url': 'https://api.github.com/repos/thethiny/dolphin/stargazers', 'contributors_url': 'https://api.github.com/repos/thethiny/dolphin/contributors', 'subscribers_url': 'https://api.github.com/repos/thethiny/dolphin/subscribers', 'subscription_url': 'https://api.github.com/repos/thethiny/dolphin/subscription', 'commits_url': 'https://api.github.com/repos/thethiny/dolphin/commits{/sha}', 'git_commits_url': 'https://api.github.com/repos/thethiny/dolphin/git/commits{/sha}', 'comments_url': 'https://api.github.com/repos/thethiny/dolphin/comments{/number}', 'issue_comment_url': 'https://api.github.com/repos/thethiny/dolphin/issues/comments{/number}', 'contents_url': 'https://api.github.com/repos/thethiny/dolphin/contents/{+path}', 'compare_url': 'https://api.github.com/repos/thethiny/dolphin/compare/{base}...{head}', 'merges_url': 'https://api.github.com/repos/thethiny/dolphin/merges', 'archive_url': 'https://api.github.com/repos/thethiny/dolphin/{archive_format}{/ref}', 'downloads_url': 'https://api.github.com/repos/thethiny/dolphin/downloads', 'issues_url': 'https://api.github.com/repos/thethiny/dolphin/issues{/number}', 'pulls_url': 'https://api.github.com/repos/thethiny/dolphin/pulls{/number}', 'milestones_url': 'https://api.github.com/repos/thethiny/dolphin/milestones{/number}', 'notifications_url': 'https://api.github.com/repos/thethiny/dolphin/notifications{?since,all,participating}', 'labels_url': 'https://api.github.com/repos/thethiny/dolphin/labels{/name}', 'releases_url': 'https://api.github.com/repos/thethiny/dolphin/releases{/id}', 'deployments_url': 'https://api.github.com/repos/thethiny/dolphin/deployments', 'created_at': '2026-07-12T22:09:13Z', 'updated_at': '2026-07-12T22:09:13Z', 'pushed_at': '2026-07-18T20:35:03Z', 'git_url': 'git://github.com/thethiny/dolphin.git', 'ssh_url': 'git@github.com:thethiny/dolphin.git', 'clone_url': 'https://github.com/thethiny/dolphin.git', 'svn_url': 'https://github.com/thethiny/dolphin', 'homepage': 'https://dolphin-emu.org', 'size': 515471, 'stargazers_count': 0, 'watchers_count': 0, 'language': None, 'has_issues': False, 'has_projects': True, 'has_downloads': True, 'has_wiki': True, 'has_pages': False, 'has_discussions': False, 'forks_count': 0, 'mirror_url': None, 'archived': False, 'disabled': False, 'open_issues_count': 0, 'license': {'key': 'other', 'name': 'Other', 'spdx_id': 'NOASSERTION', 'url': None, 'node_id': 'MDc6TGljZW5zZTA='}, 'allow_forking': True, 'is_template': False, 'web_commit_signoff_required': False, 'has_pull_requests': True, 'pull_request_creation_policy': 'all', 'topics': [], 'visibility': 'public', 'forks': 0, 'open_issues': 0, 'watchers': 0, 'default_branch': 'master', 'allow_squash_merge': True, 'allow_merge_commit': True, 'allow_rebase_merge': True, 'allow_auto_merge': False, 'delete_branch_on_merge': False, 'allow_update_branch': False, 'use_squash_pr_title_as_default': False, 'squash_merge_commit_message': 'COMMIT_MESSAGES', 'squash_merge_commit_title': 'COMMIT_OR_PR_TITLE', 'merge_commit_message': 'PR_TITLE', 'merge_commit_title': 'MERGE_MESSAGE'}}, 'base': {'label': 'dolphin-emu:master', 'ref': 'master', 'sha': 'd3b2943807dd0073f7767947466dd73cccfef319', 'user': {'login': 'dolphin-emu', 'id': 5050316, 'node_id': 'MDEyOk9yZ2FuaXphdGlvbjUwNTAzMTY=', 'avatar_url': 'https://avatars.githubusercontent.com/u/5050316?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/dolphin-emu', 'html_url': 'https://github.com/dolphin-emu', 'followers_url': 'https://api.github.com/users/dolphin-emu/followers', 'following_url': 'https://api.github.com/users/dolphin-emu/following{/other_user}', 'gists_url': 'https://api.github.com/users/dolphin-emu/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/dolphin-emu/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/dolphin-emu/subscriptions', 'organizations_url': 'https://api.github.com/users/dolphin-emu/orgs', 'repos_url': 'https://api.github.com/users/dolphin-emu/repos', 'events_url': 'https://api.github.com/users/dolphin-emu/events{/privacy}', 'received_events_url': 'https://api.github.com/users/dolphin-emu/received_events', 'type': 'Organization', 'user_view_type': 'public', 'site_admin': False}, 'repo': {'id': 11577304, 'node_id': 'MDEwOlJlcG9zaXRvcnkxMTU3NzMwNA==', 'name': 'dolphin', 'full_name': 'dolphin-emu/dolphin', 'private': False, 'owner': {'login': 'dolphin-emu', 'id': 5050316, 'node_id': 'MDEyOk9yZ2FuaXphdGlvbjUwNTAzMTY=', 'avatar_url': 'https://avatars.githubusercontent.com/u/5050316?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/dolphin-emu', 'html_url': 'https://github.com/dolphin-emu', 'followers_url': 'https://api.github.com/users/dolphin-emu/followers', 'following_url': 'https://api.github.com/users/dolphin-emu/following{/other_user}', 'gists_url': 'https://api.github.com/users/dolphin-emu/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/dolphin-emu/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/dolphin-emu/subscriptions', 'organizations_url': 'https://api.github.com/users/dolphin-emu/orgs', 'repos_url': 'https://api.github.com/users/dolphin-emu/repos', 'events_url': 'https://api.github.com/users/dolphin-emu/events{/privacy}', 'received_events_url': 'https://api.github.com/users/dolphin-emu/received_events', 'type': 'Organization', 'user_view_type': 'public', 'site_admin': False}, 'html_url': 'https://github.com/dolphin-emu/dolphin', 'description': 'Dolphin is a GameCube / Wii emulator, allowing you to play games for these two platforms on PC with improvements.', 'fork': False, 'url': 'https://api.github.com/repos/dolphin-emu/dolphin', 'forks_url': 'https://api.github.com/repos/dolphin-emu/dolphin/forks', 'keys_url': 'https://api.github.com/repos/dolphin-emu/dolphin/keys{/key_id}', 'collaborators_url': 'https://api.github.com/repos/dolphin-emu/dolphin/collaborators{/collaborator}', 'teams_url': 'https://api.github.com/repos/dolphin-emu/dolphin/teams', 'hooks_url': 'https://api.github.com/repos/dolphin-emu/dolphin/hooks', 'issue_events_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/events{/number}', 'events_url': 'https://api.github.com/repos/dolphin-emu/dolphin/events', 'assignees_url': 'https://api.github.com/repos/dolphin-emu/dolphin/assignees{/user}', 'branches_url': 'https://api.github.com/repos/dolphin-emu/dolphin/branches{/branch}', 'tags_url': 'https://api.github.com/repos/dolphin-emu/dolphin/tags', 'blobs_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/blobs{/sha}', 'git_tags_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/tags{/sha}', 'git_refs_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/refs{/sha}', 'trees_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/trees{/sha}', 'statuses_url': 'https://api.github.com/repos/dolphin-emu/dolphin/statuses/{sha}', 'languages_url': 'https://api.github.com/repos/dolphin-emu/dolphin/languages', 'stargazers_url': 'https://api.github.com/repos/dolphin-emu/dolphin/stargazers', 'contributors_url': 'https://api.github.com/repos/dolphin-emu/dolphin/contributors', 'subscribers_url': 'https://api.github.com/repos/dolphin-emu/dolphin/subscribers', 'subscription_url': 'https://api.github.com/repos/dolphin-emu/dolphin/subscription', 'commits_url': 'https://api.github.com/repos/dolphin-emu/dolphin/commits{/sha}', 'git_commits_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/commits{/sha}', 'comments_url': 'https://api.github.com/repos/dolphin-emu/dolphin/comments{/number}', 'issue_comment_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/comments{/number}', 'contents_url': 'https://api.github.com/repos/dolphin-emu/dolphin/contents/{+path}', 'compare_url': 'https://api.github.com/repos/dolphin-emu/dolphin/compare/{base}...{head}', 'merges_url': 'https://api.github.com/repos/dolphin-emu/dolphin/merges', 'archive_url': 'https://api.github.com/repos/dolphin-emu/dolphin/{archive_format}{/ref}', 'downloads_url': 'https://api.github.com/repos/dolphin-emu/dolphin/downloads', 'issues_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues{/number}', 'pulls_url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls{/number}', 'milestones_url': 'https://api.github.com/repos/dolphin-emu/dolphin/milestones{/number}', 'notifications_url': 'https://api.github.com/repos/dolphin-emu/dolphin/notifications{?since,all,participating}', 'labels_url': 'https://api.github.com/repos/dolphin-emu/dolphin/labels{/name}', 'releases_url': 'https://api.github.com/repos/dolphin-emu/dolphin/releases{/id}', 'deployments_url': 'https://api.github.com/repos/dolphin-emu/dolphin/deployments', 'created_at': '2013-07-22T09:07:57Z', 'updated_at': '2026-07-18T23:13:54Z', 'pushed_at': '2026-07-18T10:34:54Z', 'git_url': 'git://github.com/dolphin-emu/dolphin.git', 'ssh_url': 'git@github.com:dolphin-emu/dolphin.git', 'clone_url': 'https://github.com/dolphin-emu/dolphin.git', 'svn_url': 'https://github.com/dolphin-emu/dolphin', 'homepage': 'https://dolphin-emu.org', 'size': 558448, 'stargazers_count': 15273, 'watchers_count': 15273, 'language': 'C++', 'has_issues': False, 'has_projects': False, 'has_downloads': True, 'has_wiki': True, 'has_pages': False, 'has_discussions': False, 'forks_count': 3162, 'mirror_url': None, 'archived': False, 'disabled': False, 'open_issues_count': 446, 'license': {'key': 'other', 'name': 'Other', 'spdx_id': 'NOASSERTION', 'url': None, 'node_id': 'MDc6TGljZW5zZTA='}, 'allow_forking': True, 'is_template': False, 'web_commit_signoff_required': False, 'has_pull_requests': True, 'pull_request_creation_policy': 'all', 'topics': ['cpp', 'emulation', 'emulator', 'gamecube', 'wii'], 'visibility': 'public', 'forks': 3162, 'open_issues': 446, 'watchers': 15273, 'default_branch': 'master', 'allow_squash_merge': False, 'allow_merge_commit': True, 'allow_rebase_merge': False, 'allow_auto_merge': False, 'delete_branch_on_merge': False, 'allow_update_branch': False, 'use_squash_pr_title_as_default': False, 'squash_merge_commit_message': 'COMMIT_MESSAGES', 'squash_merge_commit_title': 'COMMIT_OR_PR_TITLE', 'merge_commit_message': 'PR_TITLE', 'merge_commit_title': 'MERGE_MESSAGE'}}, '_links': {'self': {'href': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/14731'}, 'html': {'href': 'https://github.com/dolphin-emu/dolphin/pull/14731'}, 'issue': {'href': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/14731'}, 'comments': {'href': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/14731/comments'}, 'review_comments': {'href': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/14731/comments'}, 'review_comment': {'href': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/comments{/number}'}, 'commits': {'href': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/14731/commits'}, 'statuses': {'href': 'https://api.github.com/repos/dolphin-emu/dolphin/statuses/24b41d58df2315831b74f76b95417f2739d02f9d'}}, 'author_association': 'NONE', 'auto_merge': None, 'assignee': None, 'active_lock_reason': None}, 'repository': {'id': 11577304, 'node_id': 'MDEwOlJlcG9zaXRvcnkxMTU3NzMwNA==', 'name': 'dolphin', 'full_name': 'dolphin-emu/dolphin', 'private': False, 'owner': {'login': 'dolphin-emu', 'id': 5050316, 'node_id': 'MDEyOk9yZ2FuaXphdGlvbjUwNTAzMTY=', 'avatar_url': 'https://avatars.githubusercontent.com/u/5050316?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/dolphin-emu', 'html_url': 'https://github.com/dolphin-emu', 'followers_url': 'https://api.github.com/users/dolphin-emu/followers', 'following_url': 'https://api.github.com/users/dolphin-emu/following{/other_user}', 'gists_url': 'https://api.github.com/users/dolphin-emu/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/dolphin-emu/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/dolphin-emu/subscriptions', 'organizations_url': 'https://api.github.com/users/dolphin-emu/orgs', 'repos_url': 'https://api.github.com/users/dolphin-emu/repos', 'events_url': 'https://api.github.com/users/dolphin-emu/events{/privacy}', 'received_events_url': 'https://api.github.com/users/dolphin-emu/received_events', 'type': 'Organization', 'user_view_type': 'public', 'site_admin': False}, 'html_url': 'https://github.com/dolphin-emu/dolphin', 'description': 'Dolphin is a GameCube / Wii emulator, allowing you to play games for these two platforms on PC with improvements.', 'fork': False, 'url': 'https://api.github.com/repos/dolphin-emu/dolphin', 'forks_url': 'https://api.github.com/repos/dolphin-emu/dolphin/forks', 'keys_url': 'https://api.github.com/repos/dolphin-emu/dolphin/keys{/key_id}', 'collaborators_url': 'https://api.github.com/repos/dolphin-emu/dolphin/collaborators{/collaborator}', 'teams_url': 'https://api.github.com/repos/dolphin-emu/dolphin/teams', 'hooks_url': 'https://api.github.com/repos/dolphin-emu/dolphin/hooks', 'issue_events_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/events{/number}', 'events_url': 'https://api.github.com/repos/dolphin-emu/dolphin/events', 'assignees_url': 'https://api.github.com/repos/dolphin-emu/dolphin/assignees{/user}', 'branches_url': 'https://api.github.com/repos/dolphin-emu/dolphin/branches{/branch}', 'tags_url': 'https://api.github.com/repos/dolphin-emu/dolphin/tags', 'blobs_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/blobs{/sha}', 'git_tags_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/tags{/sha}', 'git_refs_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/refs{/sha}', 'trees_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/trees{/sha}', 'statuses_url': 'https://api.github.com/repos/dolphin-emu/dolphin/statuses/{sha}', 'languages_url': 'https://api.github.com/repos/dolphin-emu/dolphin/languages', 'stargazers_url': 'https://api.github.com/repos/dolphin-emu/dolphin/stargazers', 'contributors_url': 'https://api.github.com/repos/dolphin-emu/dolphin/contributors', 'subscribers_url': 'https://api.github.com/repos/dolphin-emu/dolphin/subscribers', 'subscription_url': 'https://api.github.com/repos/dolphin-emu/dolphin/subscription', 'commits_url': 'https://api.github.com/repos/dolphin-emu/dolphin/commits{/sha}', 'git_commits_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/commits{/sha}', 'comments_url': 'https://api.github.com/repos/dolphin-emu/dolphin/comments{/number}', 'issue_comment_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/comments{/number}', 'contents_url': 'https://api.github.com/repos/dolphin-emu/dolphin/contents/{+path}', 'compare_url': 'https://api.github.com/repos/dolphin-emu/dolphin/compare/{base}...{head}', 'merges_url': 'https://api.github.com/repos/dolphin-emu/dolphin/merges', 'archive_url': 'https://api.github.com/repos/dolphin-emu/dolphin/{archive_format}{/ref}', 'downloads_url': 'https://api.github.com/repos/dolphin-emu/dolphin/downloads', 'issues_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues{/number}', 'pulls_url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls{/number}', 'milestones_url': 'https://api.github.com/repos/dolphin-emu/dolphin/milestones{/number}', 'notifications_url': 'https://api.github.com/repos/dolphin-emu/dolphin/notifications{?since,all,participating}', 'labels_url': 'https://api.github.com/repos/dolphin-emu/dolphin/labels{/name}', 'releases_url': 'https://api.github.com/repos/dolphin-emu/dolphin/releases{/id}', 'deployments_url': 'https://api.github.com/repos/dolphin-emu/dolphin/deployments', 'created_at': '2013-07-22T09:07:57Z', 'updated_at': '2026-07-18T23:13:54Z', 'pushed_at': '2026-07-18T10:34:54Z', 'git_url': 'git://github.com/dolphin-emu/dolphin.git', 'ssh_url': 'git@github.com:dolphin-emu/dolphin.git', 'clone_url': 'https://github.com/dolphin-emu/dolphin.git', 'svn_url': 'https://github.com/dolphin-emu/dolphin', 'homepage': 'https://dolphin-emu.org', 'size': 558448, 'stargazers_count': 15273, 'watchers_count': 15273, 'language': 'C++', 'has_issues': False, 'has_projects': False, 'has_downloads': True, 'has_wiki': True, 'has_pages': False, 'has_discussions': False, 'forks_count': 3162, 'mirror_url': None, 'archived': False, 'disabled': False, 'open_issues_count': 446, 'license': {'key': 'other', 'name': 'Other', 'spdx_id': 'NOASSERTION', 'url': None, 'node_id': 'MDc6TGljZW5zZTA='}, 'allow_forking': True, 'is_template': False, 'web_commit_signoff_required': False, 'has_pull_requests': True, 'pull_request_creation_policy': 'all', 'topics': ['cpp', 'emulation', 'emulator', 'gamecube', 'wii'], 'visibility': 'public', 'forks': 3162, 'open_issues': 446, 'watchers': 15273, 'default_branch': 'master', 'custom_properties': {}}, 'organization': {'login': 'dolphin-emu', 'id': 5050316, 'node_id': 'MDEyOk9yZ2FuaXphdGlvbjUwNTAzMTY=', 'url': 'https://api.github.com/orgs/dolphin-emu', 'repos_url': 'https://api.github.com/orgs/dolphin-emu/repos', 'events_url': 'https://api.github.com/orgs/dolphin-emu/events', 'hooks_url': 'https://api.github.com/orgs/dolphin-emu/hooks', 'issues_url': 'https://api.github.com/orgs/dolphin-emu/issues', 'members_url': 'https://api.github.com/orgs/dolphin-emu/members{/member}', 'public_members_url': 'https://api.github.com/orgs/dolphin-emu/public_members{/member}', 'avatar_url': 'https://avatars.githubusercontent.com/u/5050316?v=4', 'description': ''}, 'sender': {'login': 'thethiny', 'id': 6018214, 'node_id': 'MDQ6VXNlcjYwMTgyMTQ=', 'avatar_url': 'https://avatars.githubusercontent.com/u/6018214?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/thethiny', 'html_url': 'https://github.com/thethiny', 'followers_url': 'https://api.github.com/users/thethiny/followers', 'following_url': 'https://api.github.com/users/thethiny/following{/other_user}', 'gists_url': 'https://api.github.com/users/thethiny/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/thethiny/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/thethiny/subscriptions', 'organizations_url': 'https://api.github.com/users/thethiny/orgs', 'repos_url': 'https://api.github.com/users/thethiny/repos', 'events_url': 'https://api.github.com/users/thethiny/events{/privacy}', 'received_events_url': 'https://api.github.com/users/thethiny/received_events', 'type': 'User', 'user_view_type': 'public', 'site_admin': False}, 'installation': {'id': 35437981, 'node_id': 'MDIzOkludGVncmF0aW9uSW5zdGFsbGF0aW9uMzU0Mzc5ODE='}}, 'type': 'raw_gh_hook'}
2026-07-18T23:14:48.024476	{'source': 'webserver', 'gh_type': 'pull_request_review_comment', 'raw': {'action': 'created', 'comment': {'url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/comments/3609382108', 'pull_request_review_id': 4729467027, 'id': 3609382108, 'node_id': 'PRRC_kwDOALCn2M7XIszc', 'diff_hunk': '@@ -186,7 +380,304 @@ std::unique_ptr<WbfsFileReader> WbfsFileReader::Create(File::DirectIOFile file,\n   if (!reader->IsGood())\n     reader.reset();\n \n+  if (reader && reader->m_has_nkit_header)\n+    reader->ReadPartitionInfo();\n+\n   return reader;\n }\n \n+// Converts any disc image to WBFS with an NKit v2 header for lossless round-trips.\n+// Strips disc-level junk and partition-level junk (encrypted sectors whose decrypted\n+// content is zero or LFG padding), records a junk bitmap for reconstruction.\n+// See: https://github.com/dolphin-emu/dolphin/pull/14731\n+bool ConvertToWBFS(BlobReader* infile, const std::string& infile_path,\n+                   const std::string& outfile_path, const CompressCB& callback)\n+{\n+  ASSERT(infile->GetDataSizeType() == DataSizeType::Accurate ||\n+         infile->GetDataSizeType() == DataSizeType::UpperBound);\n+\n+  File::DirectIOFile outfile(outfile_path, File::AccessMode::Write);\n+  if (!outfile.IsOpen())\n+  {\n+    PanicAlertFmtT(\n+        "Failed to open the output file \\"{0}\\".\\n"\n+        "Check that you have permissions to write the target folder and that the media can "\n+        "be written.",\n+        outfile_path);\n+    return false;\n+  }\n+\n+  const u64 disc_size = infile->GetDataSize();\n+\n+  // These match the values used by standard WBFS tools (wwt, WBFS Manager)\n+  static constexpr u8 hd_sector_shift = 9;\n+  static constexpr u8 wbfs_sector_shift = 21;\n+  static constexpr u64 hd_sector_size = 1ull << hd_sector_shift;\n+  static constexpr u64 wbfs_sector_size = 1ull << wbfs_sector_shift;\n+\n+  const u64 blocks_per_disc = (disc_size + wbfs_sector_size - 1) / wbfs_sector_size;\n+  const u64 disc_info_size =\n+      Common::AlignUp(WII_DISC_HEADER_SIZE + blocks_per_disc * sizeof(u16), hd_sector_size);\n+\n+  // Read disc header (first 256 bytes contain disc_id, disc_num, title, etc.)\n+  std::vector<u8> disc_header(WII_DISC_HEADER_SIZE, 0);\n+  if (!infile->Read(0, WII_DISC_HEADER_SIZE, disc_header.data()))\n+  {\n+    PanicAlertFmtT("Failed to read from the input file \\"{0}\\".", infile_path);\n+    return false;\n+  }\n+\n+  // Use Volume for partition info and decrypted reads\n+  struct PartitionInfo\n+  {\n+    u64 data_offset;\n+    u64 data_size;\n+    Partition partition;\n+  };\n+  std::vector<PartitionInfo> partitions;\n+\n+  std::unique_ptr<VolumeDisc> volume = CreateDisc(infile_path);\n+  if (volume)\n+  {\n+    for (const Partition& partition : volume->GetPartitions())\n+    {\n+      const std::optional<u64> data_offset =\n+          volume->ReadSwappedAndShifted(partition.offset + 0x2B8, PARTITION_NONE);\n+      const std::optional<u64> data_size =\n+          volume->ReadSwappedAndShifted(partition.offset + 0x2BC, PARTITION_NONE);', 'path': 'Source/Core/DiscIO/WbfsBlob.cpp', 'commit_id': '24b41d58df2315831b74f76b95417f2739d02f9d', 'original_commit_id': '24b41d58df2315831b74f76b95417f2739d02f9d', 'user': {'login': 'phire', 'id': 138484, 'node_id': 'MDQ6VXNlcjEzODQ4NA==', 'avatar_url': 'https://avatars.githubusercontent.com/u/138484?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/phire', 'html_url': 'https://github.com/phire', 'followers_url': 'https://api.github.com/users/phire/followers', 'following_url': 'https://api.github.com/users/phire/following{/other_user}', 'gists_url': 'https://api.github.com/users/phire/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/phire/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/phire/subscriptions', 'organizations_url': 'https://api.github.com/users/phire/orgs', 'repos_url': 'https://api.github.com/users/phire/repos', 'events_url': 'https://api.github.com/users/phire/events{/privacy}', 'received_events_url': 'https://api.github.com/users/phire/received_events', 'type': 'User', 'user_view_type': 'public', 'site_admin': False}, 'body': 'Is this really the best way?\n\nI guess so. Maybe VolumeWii needs some refactoring to better expose partition info. ', 'created_at': '2026-07-18T23:14:45Z', 'updated_at': '2026-07-18T23:14:45Z', 'html_url': 'https://github.com/dolphin-emu/dolphin/pull/14731#discussion_r3609382108', 'pull_request_url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/14731', '_links': {'self': {'href': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/comments/3609382108'}, 'html': {'href': 'https://github.com/dolphin-emu/dolphin/pull/14731#discussion_r3609382108'}, 'pull_request': {'href': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/14731'}}, 'reactions': {'url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/comments/3609382108/reactions', 'total_count': 0, '+1': 0, '-1': 0, 'laugh': 0, 'hooray': 0, 'confused': 0, 'heart': 0, 'rocket': 0, 'eyes': 0}, 'start_line': 444, 'original_start_line': 444, 'start_side': 'RIGHT', 'line': 447, 'original_line': 447, 'side': 'RIGHT', 'author_association': 'MEMBER', 'original_position': 354, 'position': 354, 'subject_type': 'line'}, 'pull_request': {'url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/14731', 'id': 4056977334, 'node_id': 'PR_kwDOALCn2M7x0I-2', 'html_url': 'https://github.com/dolphin-emu/dolphin/pull/14731', 'diff_url': 'https://github.com/dolphin-emu/dolphin/pull/14731.diff', 'patch_url': 'https://github.com/dolphin-emu/dolphin/pull/14731.patch', 'issue_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/14731', 'number': 14731, 'state': 'open', 'locked': False, 'title': 'Convert To WBFS Support', 'user': {'login': 'thethiny', 'id': 6018214, 'node_id': 'MDQ6VXNlcjYwMTgyMTQ=', 'avatar_url': 'https://avatars.githubusercontent.com/u/6018214?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/thethiny', 'html_url': 'https://github.com/thethiny', 'followers_url': 'https://api.github.com/users/thethiny/followers', 'following_url': 'https://api.github.com/users/thethiny/following{/other_user}', 'gists_url': 'https://api.github.com/users/thethiny/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/thethiny/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/thethiny/subscriptions', 'organizations_url': 'https://api.github.com/users/thethiny/orgs', 'repos_url': 'https://api.github.com/users/thethiny/repos', 'events_url': 'https://api.github.com/users/thethiny/events{/privacy}', 'received_events_url': 'https://api.github.com/users/thethiny/received_events', 'type': 'User', 'user_view_type': 'public', 'site_admin': False}, 'body': "This PR introduces Conversion **to** WBFS support. WBFS is the format that is used by USB Loaders on a real Wii device.\r\n\r\n## Design decisions & hardcoded values\r\nThe writer uses fixed sector sizes that match what [libwbfs (the reference implementation by kwiirk)](https://github.com/kwiirk/wbfs/blob/master/libwbfs/libwbfs.c#L128-L134) computes for a standard single-layer Wii disc. These 2 hardcodes are stable and work correctly across all my testings.\r\n- HD sector shift: 9 (512 bytes)\r\n- WBFS sector shift: 21 (2 MiB)\r\nThese are not configurable via the UI. All existing WBFS tools use these values, and since the aim is to support USB Loaders then this has been tested and it is working on a real Wii.\r\n\r\nConverting from WBFS is not enabled. The existing `WbfsFileReader` reports `DataSizeType::UpperBound`, and `ShouldAllowConversion()` requires `Accurate`. I am able to support this but since it was hardcoded by the Dolphin team I thought a discussion is warranted.\r\n\r\n## Testing\r\n- Verified with DolphinTool header and DolphinTool verify\r\n- Verified with wit FILETYPE and wit DUMP (Wiimm's ISO Tools recognizes valid WBFS structure, partitions, encryption)\r\n- Tested ISO to WBFS and RVZ to WBFS conversions\r\n- Output file sizes match Wii Backup Manager when scrubbing is enabled (~0.1% difference), works when scrubbing is disabled.\r\n- Output WBFS files play correctly in Dolphin\r\n- Output WBFS files play correctly on a real Wii using USB Loader GX e25c4f3\r\n", 'created_at': '2026-07-15T01:16:25Z', 'updated_at': '2026-07-18T23:06:00Z', 'closed_at': None, 'merged_at': None, 'merge_commit_sha': '228f93416dd80eb09da834ad7852c8eaa4d9212b', 'assignees': [], 'requested_reviewers': [], 'requested_teams': [], 'labels': [], 'milestone': None, 'draft': False, 'commits_url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/14731/commits', 'review_comments_url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/14731/comments', 'review_comment_url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/comments{/number}', 'comments_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/14731/comments', 'statuses_url': 'https://api.github.com/repos/dolphin-emu/dolphin/statuses/24b41d58df2315831b74f76b95417f2739d02f9d', 'head': {'label': 'thethiny:wbfs-conversion', 'ref': 'wbfs-conversion', 'sha': '24b41d58df2315831b74f76b95417f2739d02f9d', 'user': {'login': 'thethiny', 'id': 6018214, 'node_id': 'MDQ6VXNlcjYwMTgyMTQ=', 'avatar_url': 'https://avatars.githubusercontent.com/u/6018214?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/thethiny', 'html_url': 'https://github.com/thethiny', 'followers_url': 'https://api.github.com/users/thethiny/followers', 'following_url': 'https://api.github.com/users/thethiny/following{/other_user}', 'gists_url': 'https://api.github.com/users/thethiny/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/thethiny/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/thethiny/subscriptions', 'organizations_url': 'https://api.github.com/users/thethiny/orgs', 'repos_url': 'https://api.github.com/users/thethiny/repos', 'events_url': 'https://api.github.com/users/thethiny/events{/privacy}', 'received_events_url': 'https://api.github.com/users/thethiny/received_events', 'type': 'User', 'user_view_type': 'public', 'site_admin': False}, 'repo': {'id': 1298654395, 'node_id': 'R_kgDOTWfkuw', 'name': 'dolphin', 'full_name': 'thethiny/dolphin', 'private': False, 'owner': {'login': 'thethiny', 'id': 6018214, 'node_id': 'MDQ6VXNlcjYwMTgyMTQ=', 'avatar_url': 'https://avatars.githubusercontent.com/u/6018214?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/thethiny', 'html_url': 'https://github.com/thethiny', 'followers_url': 'https://api.github.com/users/thethiny/followers', 'following_url': 'https://api.github.com/users/thethiny/following{/other_user}', 'gists_url': 'https://api.github.com/users/thethiny/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/thethiny/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/thethiny/subscriptions', 'organizations_url': 'https://api.github.com/users/thethiny/orgs', 'repos_url': 'https://api.github.com/users/thethiny/repos', 'events_url': 'https://api.github.com/users/thethiny/events{/privacy}', 'received_events_url': 'https://api.github.com/users/thethiny/received_events', 'type': 'User', 'user_view_type': 'public', 'site_admin': False}, 'html_url': 'https://github.com/thethiny/dolphin', 'description': 'Dolphin is a GameCube / Wii emulator, allowing you to play games for these two platforms on PC with improvements.', 'fork': True, 'url': 'https://api.github.com/repos/thethiny/dolphin', 'forks_url': 'https://api.github.com/repos/thethiny/dolphin/forks', 'keys_url': 'https://api.github.com/repos/thethiny/dolphin/keys{/key_id}', 'collaborators_url': 'https://api.github.com/repos/thethiny/dolphin/collaborators{/collaborator}', 'teams_url': 'https://api.github.com/repos/thethiny/dolphin/teams', 'hooks_url': 'https://api.github.com/repos/thethiny/dolphin/hooks', 'issue_events_url': 'https://api.github.com/repos/thethiny/dolphin/issues/events{/number}', 'events_url': 'https://api.github.com/repos/thethiny/dolphin/events', 'assignees_url': 'https://api.github.com/repos/thethiny/dolphin/assignees{/user}', 'branches_url': 'https://api.github.com/repos/thethiny/dolphin/branches{/branch}', 'tags_url': 'https://api.github.com/repos/thethiny/dolphin/tags', 'blobs_url': 'https://api.github.com/repos/thethiny/dolphin/git/blobs{/sha}', 'git_tags_url': 'https://api.github.com/repos/thethiny/dolphin/git/tags{/sha}', 'git_refs_url': 'https://api.github.com/repos/thethiny/dolphin/git/refs{/sha}', 'trees_url': 'https://api.github.com/repos/thethiny/dolphin/git/trees{/sha}', 'statuses_url': 'https://api.github.com/repos/thethiny/dolphin/statuses/{sha}', 'languages_url': 'https://api.github.com/repos/thethiny/dolphin/languages', 'stargazers_url': 'https://api.github.com/repos/thethiny/dolphin/stargazers', 'contributors_url': 'https://api.github.com/repos/thethiny/dolphin/contributors', 'subscribers_url': 'https://api.github.com/repos/thethiny/dolphin/subscribers', 'subscription_url': 'https://api.github.com/repos/thethiny/dolphin/subscription', 'commits_url': 'https://api.github.com/repos/thethiny/dolphin/commits{/sha}', 'git_commits_url': 'https://api.github.com/repos/thethiny/dolphin/git/commits{/sha}', 'comments_url': 'https://api.github.com/repos/thethiny/dolphin/comments{/number}', 'issue_comment_url': 'https://api.github.com/repos/thethiny/dolphin/issues/comments{/number}', 'contents_url': 'https://api.github.com/repos/thethiny/dolphin/contents/{+path}', 'compare_url': 'https://api.github.com/repos/thethiny/dolphin/compare/{base}...{head}', 'merges_url': 'https://api.github.com/repos/thethiny/dolphin/merges', 'archive_url': 'https://api.github.com/repos/thethiny/dolphin/{archive_format}{/ref}', 'downloads_url': 'https://api.github.com/repos/thethiny/dolphin/downloads', 'issues_url': 'https://api.github.com/repos/thethiny/dolphin/issues{/number}', 'pulls_url': 'https://api.github.com/repos/thethiny/dolphin/pulls{/number}', 'milestones_url': 'https://api.github.com/repos/thethiny/dolphin/milestones{/number}', 'notifications_url': 'https://api.github.com/repos/thethiny/dolphin/notifications{?since,all,participating}', 'labels_url': 'https://api.github.com/repos/thethiny/dolphin/labels{/name}', 'releases_url': 'https://api.github.com/repos/thethiny/dolphin/releases{/id}', 'deployments_url': 'https://api.github.com/repos/thethiny/dolphin/deployments', 'created_at': '2026-07-12T22:09:13Z', 'updated_at': '2026-07-12T22:09:13Z', 'pushed_at': '2026-07-18T20:35:03Z', 'git_url': 'git://github.com/thethiny/dolphin.git', 'ssh_url': 'git@github.com:thethiny/dolphin.git', 'clone_url': 'https://github.com/thethiny/dolphin.git', 'svn_url': 'https://github.com/thethiny/dolphin', 'homepage': 'https://dolphin-emu.org', 'size': 515471, 'stargazers_count': 0, 'watchers_count': 0, 'language': None, 'has_issues': False, 'has_projects': True, 'has_downloads': True, 'has_wiki': True, 'has_pages': False, 'has_discussions': False, 'forks_count': 0, 'mirror_url': None, 'archived': False, 'disabled': False, 'open_issues_count': 0, 'license': {'key': 'other', 'name': 'Other', 'spdx_id': 'NOASSERTION', 'url': None, 'node_id': 'MDc6TGljZW5zZTA='}, 'allow_forking': True, 'is_template': False, 'web_commit_signoff_required': False, 'has_pull_requests': True, 'pull_request_creation_policy': 'all', 'topics': [], 'visibility': 'public', 'forks': 0, 'open_issues': 0, 'watchers': 0, 'default_branch': 'master', 'allow_squash_merge': True, 'allow_merge_commit': True, 'allow_rebase_merge': True, 'allow_auto_merge': False, 'delete_branch_on_merge': False, 'allow_update_branch': False, 'use_squash_pr_title_as_default': False, 'squash_merge_commit_message': 'COMMIT_MESSAGES', 'squash_merge_commit_title': 'COMMIT_OR_PR_TITLE', 'merge_commit_message': 'PR_TITLE', 'merge_commit_title': 'MERGE_MESSAGE'}}, 'base': {'label': 'dolphin-emu:master', 'ref': 'master', 'sha': 'd3b2943807dd0073f7767947466dd73cccfef319', 'user': {'login': 'dolphin-emu', 'id': 5050316, 'node_id': 'MDEyOk9yZ2FuaXphdGlvbjUwNTAzMTY=', 'avatar_url': 'https://avatars.githubusercontent.com/u/5050316?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/dolphin-emu', 'html_url': 'https://github.com/dolphin-emu', 'followers_url': 'https://api.github.com/users/dolphin-emu/followers', 'following_url': 'https://api.github.com/users/dolphin-emu/following{/other_user}', 'gists_url': 'https://api.github.com/users/dolphin-emu/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/dolphin-emu/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/dolphin-emu/subscriptions', 'organizations_url': 'https://api.github.com/users/dolphin-emu/orgs', 'repos_url': 'https://api.github.com/users/dolphin-emu/repos', 'events_url': 'https://api.github.com/users/dolphin-emu/events{/privacy}', 'received_events_url': 'https://api.github.com/users/dolphin-emu/received_events', 'type': 'Organization', 'user_view_type': 'public', 'site_admin': False}, 'repo': {'id': 11577304, 'node_id': 'MDEwOlJlcG9zaXRvcnkxMTU3NzMwNA==', 'name': 'dolphin', 'full_name': 'dolphin-emu/dolphin', 'private': False, 'owner': {'login': 'dolphin-emu', 'id': 5050316, 'node_id': 'MDEyOk9yZ2FuaXphdGlvbjUwNTAzMTY=', 'avatar_url': 'https://avatars.githubusercontent.com/u/5050316?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/dolphin-emu', 'html_url': 'https://github.com/dolphin-emu', 'followers_url': 'https://api.github.com/users/dolphin-emu/followers', 'following_url': 'https://api.github.com/users/dolphin-emu/following{/other_user}', 'gists_url': 'https://api.github.com/users/dolphin-emu/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/dolphin-emu/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/dolphin-emu/subscriptions', 'organizations_url': 'https://api.github.com/users/dolphin-emu/orgs', 'repos_url': 'https://api.github.com/users/dolphin-emu/repos', 'events_url': 'https://api.github.com/users/dolphin-emu/events{/privacy}', 'received_events_url': 'https://api.github.com/users/dolphin-emu/received_events', 'type': 'Organization', 'user_view_type': 'public', 'site_admin': False}, 'html_url': 'https://github.com/dolphin-emu/dolphin', 'description': 'Dolphin is a GameCube / Wii emulator, allowing you to play games for these two platforms on PC with improvements.', 'fork': False, 'url': 'https://api.github.com/repos/dolphin-emu/dolphin', 'forks_url': 'https://api.github.com/repos/dolphin-emu/dolphin/forks', 'keys_url': 'https://api.github.com/repos/dolphin-emu/dolphin/keys{/key_id}', 'collaborators_url': 'https://api.github.com/repos/dolphin-emu/dolphin/collaborators{/collaborator}', 'teams_url': 'https://api.github.com/repos/dolphin-emu/dolphin/teams', 'hooks_url': 'https://api.github.com/repos/dolphin-emu/dolphin/hooks', 'issue_events_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/events{/number}', 'events_url': 'https://api.github.com/repos/dolphin-emu/dolphin/events', 'assignees_url': 'https://api.github.com/repos/dolphin-emu/dolphin/assignees{/user}', 'branches_url': 'https://api.github.com/repos/dolphin-emu/dolphin/branches{/branch}', 'tags_url': 'https://api.github.com/repos/dolphin-emu/dolphin/tags', 'blobs_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/blobs{/sha}', 'git_tags_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/tags{/sha}', 'git_refs_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/refs{/sha}', 'trees_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/trees{/sha}', 'statuses_url': 'https://api.github.com/repos/dolphin-emu/dolphin/statuses/{sha}', 'languages_url': 'https://api.github.com/repos/dolphin-emu/dolphin/languages', 'stargazers_url': 'https://api.github.com/repos/dolphin-emu/dolphin/stargazers', 'contributors_url': 'https://api.github.com/repos/dolphin-emu/dolphin/contributors', 'subscribers_url': 'https://api.github.com/repos/dolphin-emu/dolphin/subscribers', 'subscription_url': 'https://api.github.com/repos/dolphin-emu/dolphin/subscription', 'commits_url': 'https://api.github.com/repos/dolphin-emu/dolphin/commits{/sha}', 'git_commits_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/commits{/sha}', 'comments_url': 'https://api.github.com/repos/dolphin-emu/dolphin/comments{/number}', 'issue_comment_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/comments{/number}', 'contents_url': 'https://api.github.com/repos/dolphin-emu/dolphin/contents/{+path}', 'compare_url': 'https://api.github.com/repos/dolphin-emu/dolphin/compare/{base}...{head}', 'merges_url': 'https://api.github.com/repos/dolphin-emu/dolphin/merges', 'archive_url': 'https://api.github.com/repos/dolphin-emu/dolphin/{archive_format}{/ref}', 'downloads_url': 'https://api.github.com/repos/dolphin-emu/dolphin/downloads', 'issues_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues{/number}', 'pulls_url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls{/number}', 'milestones_url': 'https://api.github.com/repos/dolphin-emu/dolphin/milestones{/number}', 'notifications_url': 'https://api.github.com/repos/dolphin-emu/dolphin/notifications{?since,all,participating}', 'labels_url': 'https://api.github.com/repos/dolphin-emu/dolphin/labels{/name}', 'releases_url': 'https://api.github.com/repos/dolphin-emu/dolphin/releases{/id}', 'deployments_url': 'https://api.github.com/repos/dolphin-emu/dolphin/deployments', 'created_at': '2013-07-22T09:07:57Z', 'updated_at': '2026-07-18T23:13:54Z', 'pushed_at': '2026-07-18T10:34:54Z', 'git_url': 'git://github.com/dolphin-emu/dolphin.git', 'ssh_url': 'git@github.com:dolphin-emu/dolphin.git', 'clone_url': 'https://github.com/dolphin-emu/dolphin.git', 'svn_url': 'https://github.com/dolphin-emu/dolphin', 'homepage': 'https://dolphin-emu.org', 'size': 558448, 'stargazers_count': 15273, 'watchers_count': 15273, 'language': 'C++', 'has_issues': False, 'has_projects': False, 'has_downloads': True, 'has_wiki': True, 'has_pages': False, 'has_discussions': False, 'forks_count': 3162, 'mirror_url': None, 'archived': False, 'disabled': False, 'open_issues_count': 446, 'license': {'key': 'other', 'name': 'Other', 'spdx_id': 'NOASSERTION', 'url': None, 'node_id': 'MDc6TGljZW5zZTA='}, 'allow_forking': True, 'is_template': False, 'web_commit_signoff_required': False, 'has_pull_requests': True, 'pull_request_creation_policy': 'all', 'topics': ['cpp', 'emulation', 'emulator', 'gamecube', 'wii'], 'visibility': 'public', 'forks': 3162, 'open_issues': 446, 'watchers': 15273, 'default_branch': 'master', 'allow_squash_merge': False, 'allow_merge_commit': True, 'allow_rebase_merge': False, 'allow_auto_merge': False, 'delete_branch_on_merge': False, 'allow_update_branch': False, 'use_squash_pr_title_as_default': False, 'squash_merge_commit_message': 'COMMIT_MESSAGES', 'squash_merge_commit_title': 'COMMIT_OR_PR_TITLE', 'merge_commit_message': 'PR_TITLE', 'merge_commit_title': 'MERGE_MESSAGE'}}, '_links': {'self': {'href': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/14731'}, 'html': {'href': 'https://github.com/dolphin-emu/dolphin/pull/14731'}, 'issue': {'href': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/14731'}, 'comments': {'href': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/14731/comments'}, 'review_comments': {'href': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/14731/comments'}, 'review_comment': {'href': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/comments{/number}'}, 'commits': {'href': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/14731/commits'}, 'statuses': {'href': 'https://api.github.com/repos/dolphin-emu/dolphin/statuses/24b41d58df2315831b74f76b95417f2739d02f9d'}}, 'author_association': 'NONE', 'auto_merge': None, 'assignee': None, 'active_lock_reason': None}, 'repository': {'id': 11577304, 'node_id': 'MDEwOlJlcG9zaXRvcnkxMTU3NzMwNA==', 'name': 'dolphin', 'full_name': 'dolphin-emu/dolphin', 'private': False, 'owner': {'login': 'dolphin-emu', 'id': 5050316, 'node_id': 'MDEyOk9yZ2FuaXphdGlvbjUwNTAzMTY=', 'avatar_url': 'https://avatars.githubusercontent.com/u/5050316?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/dolphin-emu', 'html_url': 'https://github.com/dolphin-emu', 'followers_url': 'https://api.github.com/users/dolphin-emu/followers', 'following_url': 'https://api.github.com/users/dolphin-emu/following{/other_user}', 'gists_url': 'https://api.github.com/users/dolphin-emu/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/dolphin-emu/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/dolphin-emu/subscriptions', 'organizations_url': 'https://api.github.com/users/dolphin-emu/orgs', 'repos_url': 'https://api.github.com/users/dolphin-emu/repos', 'events_url': 'https://api.github.com/users/dolphin-emu/events{/privacy}', 'received_events_url': 'https://api.github.com/users/dolphin-emu/received_events', 'type': 'Organization', 'user_view_type': 'public', 'site_admin': False}, 'html_url': 'https://github.com/dolphin-emu/dolphin', 'description': 'Dolphin is a GameCube / Wii emulator, allowing you to play games for these two platforms on PC with improvements.', 'fork': False, 'url': 'https://api.github.com/repos/dolphin-emu/dolphin', 'forks_url': 'https://api.github.com/repos/dolphin-emu/dolphin/forks', 'keys_url': 'https://api.github.com/repos/dolphin-emu/dolphin/keys{/key_id}', 'collaborators_url': 'https://api.github.com/repos/dolphin-emu/dolphin/collaborators{/collaborator}', 'teams_url': 'https://api.github.com/repos/dolphin-emu/dolphin/teams', 'hooks_url': 'https://api.github.com/repos/dolphin-emu/dolphin/hooks', 'issue_events_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/events{/number}', 'events_url': 'https://api.github.com/repos/dolphin-emu/dolphin/events', 'assignees_url': 'https://api.github.com/repos/dolphin-emu/dolphin/assignees{/user}', 'branches_url': 'https://api.github.com/repos/dolphin-emu/dolphin/branches{/branch}', 'tags_url': 'https://api.github.com/repos/dolphin-emu/dolphin/tags', 'blobs_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/blobs{/sha}', 'git_tags_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/tags{/sha}', 'git_refs_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/refs{/sha}', 'trees_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/trees{/sha}', 'statuses_url': 'https://api.github.com/repos/dolphin-emu/dolphin/statuses/{sha}', 'languages_url': 'https://api.github.com/repos/dolphin-emu/dolphin/languages', 'stargazers_url': 'https://api.github.com/repos/dolphin-emu/dolphin/stargazers', 'contributors_url': 'https://api.github.com/repos/dolphin-emu/dolphin/contributors', 'subscribers_url': 'https://api.github.com/repos/dolphin-emu/dolphin/subscribers', 'subscription_url': 'https://api.github.com/repos/dolphin-emu/dolphin/subscription', 'commits_url': 'https://api.github.com/repos/dolphin-emu/dolphin/commits{/sha}', 'git_commits_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/commits{/sha}', 'comments_url': 'https://api.github.com/repos/dolphin-emu/dolphin/comments{/number}', 'issue_comment_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/comments{/number}', 'contents_url': 'https://api.github.com/repos/dolphin-emu/dolphin/contents/{+path}', 'compare_url': 'https://api.github.com/repos/dolphin-emu/dolphin/compare/{base}...{head}', 'merges_url': 'https://api.github.com/repos/dolphin-emu/dolphin/merges', 'archive_url': 'https://api.github.com/repos/dolphin-emu/dolphin/{archive_format}{/ref}', 'downloads_url': 'https://api.github.com/repos/dolphin-emu/dolphin/downloads', 'issues_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues{/number}', 'pulls_url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls{/number}', 'milestones_url': 'https://api.github.com/repos/dolphin-emu/dolphin/milestones{/number}', 'notifications_url': 'https://api.github.com/repos/dolphin-emu/dolphin/notifications{?since,all,participating}', 'labels_url': 'https://api.github.com/repos/dolphin-emu/dolphin/labels{/name}', 'releases_url': 'https://api.github.com/repos/dolphin-emu/dolphin/releases{/id}', 'deployments_url': 'https://api.github.com/repos/dolphin-emu/dolphin/deployments', 'created_at': '2013-07-22T09:07:57Z', 'updated_at': '2026-07-18T23:13:54Z', 'pushed_at': '2026-07-18T10:34:54Z', 'git_url': 'git://github.com/dolphin-emu/dolphin.git', 'ssh_url': 'git@github.com:dolphin-emu/dolphin.git', 'clone_url': 'https://github.com/dolphin-emu/dolphin.git', 'svn_url': 'https://github.com/dolphin-emu/dolphin', 'homepage': 'https://dolphin-emu.org', 'size': 558448, 'stargazers_count': 15273, 'watchers_count': 15273, 'language': 'C++', 'has_issues': False, 'has_projects': False, 'has_downloads': True, 'has_wiki': True, 'has_pages': False, 'has_discussions': False, 'forks_count': 3162, 'mirror_url': None, 'archived': False, 'disabled': False, 'open_issues_count': 446, 'license': {'key': 'other', 'name': 'Other', 'spdx_id': 'NOASSERTION', 'url': None, 'node_id': 'MDc6TGljZW5zZTA='}, 'allow_forking': True, 'is_template': False, 'web_commit_signoff_required': False, 'has_pull_requests': True, 'pull_request_creation_policy': 'all', 'topics': ['cpp', 'emulation', 'emulator', 'gamecube', 'wii'], 'visibility': 'public', 'forks': 3162, 'open_issues': 446, 'watchers': 15273, 'default_branch': 'master', 'custom_properties': {}}, 'organization': {'login': 'dolphin-emu', 'id': 5050316, 'node_id': 'MDEyOk9yZ2FuaXphdGlvbjUwNTAzMTY=', 'url': 'https://api.github.com/orgs/dolphin-emu', 'repos_url': 'https://api.github.com/orgs/dolphin-emu/repos', 'events_url': 'https://api.github.com/orgs/dolphin-emu/events', 'hooks_url': 'https://api.github.com/orgs/dolphin-emu/hooks', 'issues_url': 'https://api.github.com/orgs/dolphin-emu/issues', 'members_url': 'https://api.github.com/orgs/dolphin-emu/members{/member}', 'public_members_url': 'https://api.github.com/orgs/dolphin-emu/public_members{/member}', 'avatar_url': 'https://avatars.githubusercontent.com/u/5050316?v=4', 'description': ''}, 'sender': {'login': 'phire', 'id': 138484, 'node_id': 'MDQ6VXNlcjEzODQ4NA==', 'avatar_url': 'https://avatars.githubusercontent.com/u/138484?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/phire', 'html_url': 'https://github.com/phire', 'followers_url': 'https://api.github.com/users/phire/followers', 'following_url': 'https://api.github.com/users/phire/following{/other_user}', 'gists_url': 'https://api.github.com/users/phire/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/phire/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/phire/subscriptions', 'organizations_url': 'https://api.github.com/users/phire/orgs', 'repos_url': 'https://api.github.com/users/phire/repos', 'events_url': 'https://api.github.com/users/phire/events{/privacy}', 'received_events_url': 'https://api.github.com/users/phire/received_events', 'type': 'User', 'user_view_type': 'public', 'site_admin': False}, 'installation': {'id': 35437981, 'node_id': 'MDIzOkludGVncmF0aW9uSW5zdGFsbGF0aW9uMzU0Mzc5ODE='}}, 'type': 'raw_gh_hook'}
2026-07-18T23:14:47.908883	{'source': 'webserver', 'gh_type': 'pull_request_review', 'raw': {'action': 'submitted', 'review': {'id': 4729467027, 'node_id': 'PRR_kwDOALCn2M8AAAABGeXwkw', 'user': {'login': 'phire', 'id': 138484, 'node_id': 'MDQ6VXNlcjEzODQ4NA==', 'avatar_url': 'https://avatars.githubusercontent.com/u/138484?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/phire', 'html_url': 'https://github.com/phire', 'followers_url': 'https://api.github.com/users/phire/followers', 'following_url': 'https://api.github.com/users/phire/following{/other_user}', 'gists_url': 'https://api.github.com/users/phire/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/phire/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/phire/subscriptions', 'organizations_url': 'https://api.github.com/users/phire/orgs', 'repos_url': 'https://api.github.com/users/phire/repos', 'events_url': 'https://api.github.com/users/phire/events{/privacy}', 'received_events_url': 'https://api.github.com/users/phire/received_events', 'type': 'User', 'user_view_type': 'public', 'site_admin': False}, 'body': None, 'commit_id': '24b41d58df2315831b74f76b95417f2739d02f9d', 'state': 'commented', 'html_url': 'https://github.com/dolphin-emu/dolphin/pull/14731#pullrequestreview-4729467027', 'pull_request_url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/14731', '_links': {'html': {'href': 'https://github.com/dolphin-emu/dolphin/pull/14731#pullrequestreview-4729467027'}, 'pull_request': {'href': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/14731'}}, 'submitted_at': '2026-07-18T23:14:45Z', 'updated_at': '2026-07-18T23:14:45Z', 'author_association': 'MEMBER'}, 'pull_request': {'url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/14731', 'id': 4056977334, 'node_id': 'PR_kwDOALCn2M7x0I-2', 'html_url': 'https://github.com/dolphin-emu/dolphin/pull/14731', 'diff_url': 'https://github.com/dolphin-emu/dolphin/pull/14731.diff', 'patch_url': 'https://github.com/dolphin-emu/dolphin/pull/14731.patch', 'issue_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/14731', 'number': 14731, 'state': 'open', 'locked': False, 'title': 'Convert To WBFS Support', 'user': {'login': 'thethiny', 'id': 6018214, 'node_id': 'MDQ6VXNlcjYwMTgyMTQ=', 'avatar_url': 'https://avatars.githubusercontent.com/u/6018214?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/thethiny', 'html_url': 'https://github.com/thethiny', 'followers_url': 'https://api.github.com/users/thethiny/followers', 'following_url': 'https://api.github.com/users/thethiny/following{/other_user}', 'gists_url': 'https://api.github.com/users/thethiny/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/thethiny/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/thethiny/subscriptions', 'organizations_url': 'https://api.github.com/users/thethiny/orgs', 'repos_url': 'https://api.github.com/users/thethiny/repos', 'events_url': 'https://api.github.com/users/thethiny/events{/privacy}', 'received_events_url': 'https://api.github.com/users/thethiny/received_events', 'type': 'User', 'user_view_type': 'public', 'site_admin': False}, 'body': "This PR introduces Conversion **to** WBFS support. WBFS is the format that is used by USB Loaders on a real Wii device.\r\n\r\n## Design decisions & hardcoded values\r\nThe writer uses fixed sector sizes that match what [libwbfs (the reference implementation by kwiirk)](https://github.com/kwiirk/wbfs/blob/master/libwbfs/libwbfs.c#L128-L134) computes for a standard single-layer Wii disc. These 2 hardcodes are stable and work correctly across all my testings.\r\n- HD sector shift: 9 (512 bytes)\r\n- WBFS sector shift: 21 (2 MiB)\r\nThese are not configurable via the UI. All existing WBFS tools use these values, and since the aim is to support USB Loaders then this has been tested and it is working on a real Wii.\r\n\r\nConverting from WBFS is not enabled. The existing `WbfsFileReader` reports `DataSizeType::UpperBound`, and `ShouldAllowConversion()` requires `Accurate`. I am able to support this but since it was hardcoded by the Dolphin team I thought a discussion is warranted.\r\n\r\n## Testing\r\n- Verified with DolphinTool header and DolphinTool verify\r\n- Verified with wit FILETYPE and wit DUMP (Wiimm's ISO Tools recognizes valid WBFS structure, partitions, encryption)\r\n- Tested ISO to WBFS and RVZ to WBFS conversions\r\n- Output file sizes match Wii Backup Manager when scrubbing is enabled (~0.1% difference), works when scrubbing is disabled.\r\n- Output WBFS files play correctly in Dolphin\r\n- Output WBFS files play correctly on a real Wii using USB Loader GX e25c4f3\r\n", 'created_at': '2026-07-15T01:16:25Z', 'updated_at': '2026-07-18T23:06:00Z', 'closed_at': None, 'merged_at': None, 'merge_commit_sha': '228f93416dd80eb09da834ad7852c8eaa4d9212b', 'assignees': [], 'requested_reviewers': [], 'requested_teams': [], 'labels': [], 'milestone': None, 'draft': False, 'commits_url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/14731/commits', 'review_comments_url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/14731/comments', 'review_comment_url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/comments{/number}', 'comments_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/14731/comments', 'statuses_url': 'https://api.github.com/repos/dolphin-emu/dolphin/statuses/24b41d58df2315831b74f76b95417f2739d02f9d', 'head': {'label': 'thethiny:wbfs-conversion', 'ref': 'wbfs-conversion', 'sha': '24b41d58df2315831b74f76b95417f2739d02f9d', 'user': {'login': 'thethiny', 'id': 6018214, 'node_id': 'MDQ6VXNlcjYwMTgyMTQ=', 'avatar_url': 'https://avatars.githubusercontent.com/u/6018214?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/thethiny', 'html_url': 'https://github.com/thethiny', 'followers_url': 'https://api.github.com/users/thethiny/followers', 'following_url': 'https://api.github.com/users/thethiny/following{/other_user}', 'gists_url': 'https://api.github.com/users/thethiny/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/thethiny/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/thethiny/subscriptions', 'organizations_url': 'https://api.github.com/users/thethiny/orgs', 'repos_url': 'https://api.github.com/users/thethiny/repos', 'events_url': 'https://api.github.com/users/thethiny/events{/privacy}', 'received_events_url': 'https://api.github.com/users/thethiny/received_events', 'type': 'User', 'user_view_type': 'public', 'site_admin': False}, 'repo': {'id': 1298654395, 'node_id': 'R_kgDOTWfkuw', 'name': 'dolphin', 'full_name': 'thethiny/dolphin', 'private': False, 'owner': {'login': 'thethiny', 'id': 6018214, 'node_id': 'MDQ6VXNlcjYwMTgyMTQ=', 'avatar_url': 'https://avatars.githubusercontent.com/u/6018214?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/thethiny', 'html_url': 'https://github.com/thethiny', 'followers_url': 'https://api.github.com/users/thethiny/followers', 'following_url': 'https://api.github.com/users/thethiny/following{/other_user}', 'gists_url': 'https://api.github.com/users/thethiny/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/thethiny/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/thethiny/subscriptions', 'organizations_url': 'https://api.github.com/users/thethiny/orgs', 'repos_url': 'https://api.github.com/users/thethiny/repos', 'events_url': 'https://api.github.com/users/thethiny/events{/privacy}', 'received_events_url': 'https://api.github.com/users/thethiny/received_events', 'type': 'User', 'user_view_type': 'public', 'site_admin': False}, 'html_url': 'https://github.com/thethiny/dolphin', 'description': 'Dolphin is a GameCube / Wii emulator, allowing you to play games for these two platforms on PC with improvements.', 'fork': True, 'url': 'https://api.github.com/repos/thethiny/dolphin', 'forks_url': 'https://api.github.com/repos/thethiny/dolphin/forks', 'keys_url': 'https://api.github.com/repos/thethiny/dolphin/keys{/key_id}', 'collaborators_url': 'https://api.github.com/repos/thethiny/dolphin/collaborators{/collaborator}', 'teams_url': 'https://api.github.com/repos/thethiny/dolphin/teams', 'hooks_url': 'https://api.github.com/repos/thethiny/dolphin/hooks', 'issue_events_url': 'https://api.github.com/repos/thethiny/dolphin/issues/events{/number}', 'events_url': 'https://api.github.com/repos/thethiny/dolphin/events', 'assignees_url': 'https://api.github.com/repos/thethiny/dolphin/assignees{/user}', 'branches_url': 'https://api.github.com/repos/thethiny/dolphin/branches{/branch}', 'tags_url': 'https://api.github.com/repos/thethiny/dolphin/tags', 'blobs_url': 'https://api.github.com/repos/thethiny/dolphin/git/blobs{/sha}', 'git_tags_url': 'https://api.github.com/repos/thethiny/dolphin/git/tags{/sha}', 'git_refs_url': 'https://api.github.com/repos/thethiny/dolphin/git/refs{/sha}', 'trees_url': 'https://api.github.com/repos/thethiny/dolphin/git/trees{/sha}', 'statuses_url': 'https://api.github.com/repos/thethiny/dolphin/statuses/{sha}', 'languages_url': 'https://api.github.com/repos/thethiny/dolphin/languages', 'stargazers_url': 'https://api.github.com/repos/thethiny/dolphin/stargazers', 'contributors_url': 'https://api.github.com/repos/thethiny/dolphin/contributors', 'subscribers_url': 'https://api.github.com/repos/thethiny/dolphin/subscribers', 'subscription_url': 'https://api.github.com/repos/thethiny/dolphin/subscription', 'commits_url': 'https://api.github.com/repos/thethiny/dolphin/commits{/sha}', 'git_commits_url': 'https://api.github.com/repos/thethiny/dolphin/git/commits{/sha}', 'comments_url': 'https://api.github.com/repos/thethiny/dolphin/comments{/number}', 'issue_comment_url': 'https://api.github.com/repos/thethiny/dolphin/issues/comments{/number}', 'contents_url': 'https://api.github.com/repos/thethiny/dolphin/contents/{+path}', 'compare_url': 'https://api.github.com/repos/thethiny/dolphin/compare/{base}...{head}', 'merges_url': 'https://api.github.com/repos/thethiny/dolphin/merges', 'archive_url': 'https://api.github.com/repos/thethiny/dolphin/{archive_format}{/ref}', 'downloads_url': 'https://api.github.com/repos/thethiny/dolphin/downloads', 'issues_url': 'https://api.github.com/repos/thethiny/dolphin/issues{/number}', 'pulls_url': 'https://api.github.com/repos/thethiny/dolphin/pulls{/number}', 'milestones_url': 'https://api.github.com/repos/thethiny/dolphin/milestones{/number}', 'notifications_url': 'https://api.github.com/repos/thethiny/dolphin/notifications{?since,all,participating}', 'labels_url': 'https://api.github.com/repos/thethiny/dolphin/labels{/name}', 'releases_url': 'https://api.github.com/repos/thethiny/dolphin/releases{/id}', 'deployments_url': 'https://api.github.com/repos/thethiny/dolphin/deployments', 'created_at': '2026-07-12T22:09:13Z', 'updated_at': '2026-07-12T22:09:13Z', 'pushed_at': '2026-07-18T20:35:03Z', 'git_url': 'git://github.com/thethiny/dolphin.git', 'ssh_url': 'git@github.com:thethiny/dolphin.git', 'clone_url': 'https://github.com/thethiny/dolphin.git', 'svn_url': 'https://github.com/thethiny/dolphin', 'homepage': 'https://dolphin-emu.org', 'size': 515471, 'stargazers_count': 0, 'watchers_count': 0, 'language': None, 'has_issues': False, 'has_projects': True, 'has_downloads': True, 'has_wiki': True, 'has_pages': False, 'has_discussions': False, 'forks_count': 0, 'mirror_url': None, 'archived': False, 'disabled': False, 'open_issues_count': 0, 'license': {'key': 'other', 'name': 'Other', 'spdx_id': 'NOASSERTION', 'url': None, 'node_id': 'MDc6TGljZW5zZTA='}, 'allow_forking': True, 'is_template': False, 'web_commit_signoff_required': False, 'has_pull_requests': True, 'pull_request_creation_policy': 'all', 'topics': [], 'visibility': 'public', 'forks': 0, 'open_issues': 0, 'watchers': 0, 'default_branch': 'master', 'allow_squash_merge': True, 'allow_merge_commit': True, 'allow_rebase_merge': True, 'allow_auto_merge': False, 'delete_branch_on_merge': False, 'allow_update_branch': False, 'use_squash_pr_title_as_default': False, 'squash_merge_commit_message': 'COMMIT_MESSAGES', 'squash_merge_commit_title': 'COMMIT_OR_PR_TITLE', 'merge_commit_message': 'PR_TITLE', 'merge_commit_title': 'MERGE_MESSAGE'}}, 'base': {'label': 'dolphin-emu:master', 'ref': 'master', 'sha': 'd3b2943807dd0073f7767947466dd73cccfef319', 'user': {'login': 'dolphin-emu', 'id': 5050316, 'node_id': 'MDEyOk9yZ2FuaXphdGlvbjUwNTAzMTY=', 'avatar_url': 'https://avatars.githubusercontent.com/u/5050316?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/dolphin-emu', 'html_url': 'https://github.com/dolphin-emu', 'followers_url': 'https://api.github.com/users/dolphin-emu/followers', 'following_url': 'https://api.github.com/users/dolphin-emu/following{/other_user}', 'gists_url': 'https://api.github.com/users/dolphin-emu/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/dolphin-emu/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/dolphin-emu/subscriptions', 'organizations_url': 'https://api.github.com/users/dolphin-emu/orgs', 'repos_url': 'https://api.github.com/users/dolphin-emu/repos', 'events_url': 'https://api.github.com/users/dolphin-emu/events{/privacy}', 'received_events_url': 'https://api.github.com/users/dolphin-emu/received_events', 'type': 'Organization', 'user_view_type': 'public', 'site_admin': False}, 'repo': {'id': 11577304, 'node_id': 'MDEwOlJlcG9zaXRvcnkxMTU3NzMwNA==', 'name': 'dolphin', 'full_name': 'dolphin-emu/dolphin', 'private': False, 'owner': {'login': 'dolphin-emu', 'id': 5050316, 'node_id': 'MDEyOk9yZ2FuaXphdGlvbjUwNTAzMTY=', 'avatar_url': 'https://avatars.githubusercontent.com/u/5050316?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/dolphin-emu', 'html_url': 'https://github.com/dolphin-emu', 'followers_url': 'https://api.github.com/users/dolphin-emu/followers', 'following_url': 'https://api.github.com/users/dolphin-emu/following{/other_user}', 'gists_url': 'https://api.github.com/users/dolphin-emu/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/dolphin-emu/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/dolphin-emu/subscriptions', 'organizations_url': 'https://api.github.com/users/dolphin-emu/orgs', 'repos_url': 'https://api.github.com/users/dolphin-emu/repos', 'events_url': 'https://api.github.com/users/dolphin-emu/events{/privacy}', 'received_events_url': 'https://api.github.com/users/dolphin-emu/received_events', 'type': 'Organization', 'user_view_type': 'public', 'site_admin': False}, 'html_url': 'https://github.com/dolphin-emu/dolphin', 'description': 'Dolphin is a GameCube / Wii emulator, allowing you to play games for these two platforms on PC with improvements.', 'fork': False, 'url': 'https://api.github.com/repos/dolphin-emu/dolphin', 'forks_url': 'https://api.github.com/repos/dolphin-emu/dolphin/forks', 'keys_url': 'https://api.github.com/repos/dolphin-emu/dolphin/keys{/key_id}', 'collaborators_url': 'https://api.github.com/repos/dolphin-emu/dolphin/collaborators{/collaborator}', 'teams_url': 'https://api.github.com/repos/dolphin-emu/dolphin/teams', 'hooks_url': 'https://api.github.com/repos/dolphin-emu/dolphin/hooks', 'issue_events_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/events{/number}', 'events_url': 'https://api.github.com/repos/dolphin-emu/dolphin/events', 'assignees_url': 'https://api.github.com/repos/dolphin-emu/dolphin/assignees{/user}', 'branches_url': 'https://api.github.com/repos/dolphin-emu/dolphin/branches{/branch}', 'tags_url': 'https://api.github.com/repos/dolphin-emu/dolphin/tags', 'blobs_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/blobs{/sha}', 'git_tags_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/tags{/sha}', 'git_refs_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/refs{/sha}', 'trees_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/trees{/sha}', 'statuses_url': 'https://api.github.com/repos/dolphin-emu/dolphin/statuses/{sha}', 'languages_url': 'https://api.github.com/repos/dolphin-emu/dolphin/languages', 'stargazers_url': 'https://api.github.com/repos/dolphin-emu/dolphin/stargazers', 'contributors_url': 'https://api.github.com/repos/dolphin-emu/dolphin/contributors', 'subscribers_url': 'https://api.github.com/repos/dolphin-emu/dolphin/subscribers', 'subscription_url': 'https://api.github.com/repos/dolphin-emu/dolphin/subscription', 'commits_url': 'https://api.github.com/repos/dolphin-emu/dolphin/commits{/sha}', 'git_commits_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/commits{/sha}', 'comments_url': 'https://api.github.com/repos/dolphin-emu/dolphin/comments{/number}', 'issue_comment_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/comments{/number}', 'contents_url': 'https://api.github.com/repos/dolphin-emu/dolphin/contents/{+path}', 'compare_url': 'https://api.github.com/repos/dolphin-emu/dolphin/compare/{base}...{head}', 'merges_url': 'https://api.github.com/repos/dolphin-emu/dolphin/merges', 'archive_url': 'https://api.github.com/repos/dolphin-emu/dolphin/{archive_format}{/ref}', 'downloads_url': 'https://api.github.com/repos/dolphin-emu/dolphin/downloads', 'issues_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues{/number}', 'pulls_url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls{/number}', 'milestones_url': 'https://api.github.com/repos/dolphin-emu/dolphin/milestones{/number}', 'notifications_url': 'https://api.github.com/repos/dolphin-emu/dolphin/notifications{?since,all,participating}', 'labels_url': 'https://api.github.com/repos/dolphin-emu/dolphin/labels{/name}', 'releases_url': 'https://api.github.com/repos/dolphin-emu/dolphin/releases{/id}', 'deployments_url': 'https://api.github.com/repos/dolphin-emu/dolphin/deployments', 'created_at': '2013-07-22T09:07:57Z', 'updated_at': '2026-07-18T23:13:54Z', 'pushed_at': '2026-07-18T10:34:54Z', 'git_url': 'git://github.com/dolphin-emu/dolphin.git', 'ssh_url': 'git@github.com:dolphin-emu/dolphin.git', 'clone_url': 'https://github.com/dolphin-emu/dolphin.git', 'svn_url': 'https://github.com/dolphin-emu/dolphin', 'homepage': 'https://dolphin-emu.org', 'size': 558448, 'stargazers_count': 15273, 'watchers_count': 15273, 'language': 'C++', 'has_issues': False, 'has_projects': False, 'has_downloads': True, 'has_wiki': True, 'has_pages': False, 'has_discussions': False, 'forks_count': 3162, 'mirror_url': None, 'archived': False, 'disabled': False, 'open_issues_count': 446, 'license': {'key': 'other', 'name': 'Other', 'spdx_id': 'NOASSERTION', 'url': None, 'node_id': 'MDc6TGljZW5zZTA='}, 'allow_forking': True, 'is_template': False, 'web_commit_signoff_required': False, 'has_pull_requests': True, 'pull_request_creation_policy': 'all', 'topics': ['cpp', 'emulation', 'emulator', 'gamecube', 'wii'], 'visibility': 'public', 'forks': 3162, 'open_issues': 446, 'watchers': 15273, 'default_branch': 'master', 'allow_squash_merge': False, 'allow_merge_commit': True, 'allow_rebase_merge': False, 'allow_auto_merge': False, 'delete_branch_on_merge': False, 'allow_update_branch': False, 'use_squash_pr_title_as_default': False, 'squash_merge_commit_message': 'COMMIT_MESSAGES', 'squash_merge_commit_title': 'COMMIT_OR_PR_TITLE', 'merge_commit_message': 'PR_TITLE', 'merge_commit_title': 'MERGE_MESSAGE'}}, '_links': {'self': {'href': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/14731'}, 'html': {'href': 'https://github.com/dolphin-emu/dolphin/pull/14731'}, 'issue': {'href': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/14731'}, 'comments': {'href': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/14731/comments'}, 'review_comments': {'href': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/14731/comments'}, 'review_comment': {'href': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/comments{/number}'}, 'commits': {'href': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/14731/commits'}, 'statuses': {'href': 'https://api.github.com/repos/dolphin-emu/dolphin/statuses/24b41d58df2315831b74f76b95417f2739d02f9d'}}, 'author_association': 'NONE', 'auto_merge': None, 'assignee': None, 'active_lock_reason': None}, 'repository': {'id': 11577304, 'node_id': 'MDEwOlJlcG9zaXRvcnkxMTU3NzMwNA==', 'name': 'dolphin', 'full_name': 'dolphin-emu/dolphin', 'private': False, 'owner': {'login': 'dolphin-emu', 'id': 5050316, 'node_id': 'MDEyOk9yZ2FuaXphdGlvbjUwNTAzMTY=', 'avatar_url': 'https://avatars.githubusercontent.com/u/5050316?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/dolphin-emu', 'html_url': 'https://github.com/dolphin-emu', 'followers_url': 'https://api.github.com/users/dolphin-emu/followers', 'following_url': 'https://api.github.com/users/dolphin-emu/following{/other_user}', 'gists_url': 'https://api.github.com/users/dolphin-emu/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/dolphin-emu/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/dolphin-emu/subscriptions', 'organizations_url': 'https://api.github.com/users/dolphin-emu/orgs', 'repos_url': 'https://api.github.com/users/dolphin-emu/repos', 'events_url': 'https://api.github.com/users/dolphin-emu/events{/privacy}', 'received_events_url': 'https://api.github.com/users/dolphin-emu/received_events', 'type': 'Organization', 'user_view_type': 'public', 'site_admin': False}, 'html_url': 'https://github.com/dolphin-emu/dolphin', 'description': 'Dolphin is a GameCube / Wii emulator, allowing you to play games for these two platforms on PC with improvements.', 'fork': False, 'url': 'https://api.github.com/repos/dolphin-emu/dolphin', 'forks_url': 'https://api.github.com/repos/dolphin-emu/dolphin/forks', 'keys_url': 'https://api.github.com/repos/dolphin-emu/dolphin/keys{/key_id}', 'collaborators_url': 'https://api.github.com/repos/dolphin-emu/dolphin/collaborators{/collaborator}', 'teams_url': 'https://api.github.com/repos/dolphin-emu/dolphin/teams', 'hooks_url': 'https://api.github.com/repos/dolphin-emu/dolphin/hooks', 'issue_events_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/events{/number}', 'events_url': 'https://api.github.com/repos/dolphin-emu/dolphin/events', 'assignees_url': 'https://api.github.com/repos/dolphin-emu/dolphin/assignees{/user}', 'branches_url': 'https://api.github.com/repos/dolphin-emu/dolphin/branches{/branch}', 'tags_url': 'https://api.github.com/repos/dolphin-emu/dolphin/tags', 'blobs_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/blobs{/sha}', 'git_tags_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/tags{/sha}', 'git_refs_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/refs{/sha}', 'trees_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/trees{/sha}', 'statuses_url': 'https://api.github.com/repos/dolphin-emu/dolphin/statuses/{sha}', 'languages_url': 'https://api.github.com/repos/dolphin-emu/dolphin/languages', 'stargazers_url': 'https://api.github.com/repos/dolphin-emu/dolphin/stargazers', 'contributors_url': 'https://api.github.com/repos/dolphin-emu/dolphin/contributors', 'subscribers_url': 'https://api.github.com/repos/dolphin-emu/dolphin/subscribers', 'subscription_url': 'https://api.github.com/repos/dolphin-emu/dolphin/subscription', 'commits_url': 'https://api.github.com/repos/dolphin-emu/dolphin/commits{/sha}', 'git_commits_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/commits{/sha}', 'comments_url': 'https://api.github.com/repos/dolphin-emu/dolphin/comments{/number}', 'issue_comment_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/comments{/number}', 'contents_url': 'https://api.github.com/repos/dolphin-emu/dolphin/contents/{+path}', 'compare_url': 'https://api.github.com/repos/dolphin-emu/dolphin/compare/{base}...{head}', 'merges_url': 'https://api.github.com/repos/dolphin-emu/dolphin/merges', 'archive_url': 'https://api.github.com/repos/dolphin-emu/dolphin/{archive_format}{/ref}', 'downloads_url': 'https://api.github.com/repos/dolphin-emu/dolphin/downloads', 'issues_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues{/number}', 'pulls_url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls{/number}', 'milestones_url': 'https://api.github.com/repos/dolphin-emu/dolphin/milestones{/number}', 'notifications_url': 'https://api.github.com/repos/dolphin-emu/dolphin/notifications{?since,all,participating}', 'labels_url': 'https://api.github.com/repos/dolphin-emu/dolphin/labels{/name}', 'releases_url': 'https://api.github.com/repos/dolphin-emu/dolphin/releases{/id}', 'deployments_url': 'https://api.github.com/repos/dolphin-emu/dolphin/deployments', 'created_at': '2013-07-22T09:07:57Z', 'updated_at': '2026-07-18T23:13:54Z', 'pushed_at': '2026-07-18T10:34:54Z', 'git_url': 'git://github.com/dolphin-emu/dolphin.git', 'ssh_url': 'git@github.com:dolphin-emu/dolphin.git', 'clone_url': 'https://github.com/dolphin-emu/dolphin.git', 'svn_url': 'https://github.com/dolphin-emu/dolphin', 'homepage': 'https://dolphin-emu.org', 'size': 558448, 'stargazers_count': 15273, 'watchers_count': 15273, 'language': 'C++', 'has_issues': False, 'has_projects': False, 'has_downloads': True, 'has_wiki': True, 'has_pages': False, 'has_discussions': False, 'forks_count': 3162, 'mirror_url': None, 'archived': False, 'disabled': False, 'open_issues_count': 446, 'license': {'key': 'other', 'name': 'Other', 'spdx_id': 'NOASSERTION', 'url': None, 'node_id': 'MDc6TGljZW5zZTA='}, 'allow_forking': True, 'is_template': False, 'web_commit_signoff_required': False, 'has_pull_requests': True, 'pull_request_creation_policy': 'all', 'topics': ['cpp', 'emulation', 'emulator', 'gamecube', 'wii'], 'visibility': 'public', 'forks': 3162, 'open_issues': 446, 'watchers': 15273, 'default_branch': 'master', 'custom_properties': {}}, 'organization': {'login': 'dolphin-emu', 'id': 5050316, 'node_id': 'MDEyOk9yZ2FuaXphdGlvbjUwNTAzMTY=', 'url': 'https://api.github.com/orgs/dolphin-emu', 'repos_url': 'https://api.github.com/orgs/dolphin-emu/repos', 'events_url': 'https://api.github.com/orgs/dolphin-emu/events', 'hooks_url': 'https://api.github.com/orgs/dolphin-emu/hooks', 'issues_url': 'https://api.github.com/orgs/dolphin-emu/issues', 'members_url': 'https://api.github.com/orgs/dolphin-emu/members{/member}', 'public_members_url': 'https://api.github.com/orgs/dolphin-emu/public_members{/member}', 'avatar_url': 'https://avatars.githubusercontent.com/u/5050316?v=4', 'description': ''}, 'sender': {'login': 'phire', 'id': 138484, 'node_id': 'MDQ6VXNlcjEzODQ4NA==', 'avatar_url': 'https://avatars.githubusercontent.com/u/138484?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/phire', 'html_url': 'https://github.com/phire', 'followers_url': 'https://api.github.com/users/phire/followers', 'following_url': 'https://api.github.com/users/phire/following{/other_user}', 'gists_url': 'https://api.github.com/users/phire/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/phire/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/phire/subscriptions', 'organizations_url': 'https://api.github.com/users/phire/orgs', 'repos_url': 'https://api.github.com/users/phire/repos', 'events_url': 'https://api.github.com/users/phire/events{/privacy}', 'received_events_url': 'https://api.github.com/users/phire/received_events', 'type': 'User', 'user_view_type': 'public', 'site_admin': False}, 'installation': {'id': 35437981, 'node_id': 'MDIzOkludGVncmF0aW9uSW5zdGFsbGF0aW9uMzU0Mzc5ODE='}}, 'type': 'raw_gh_hook'}
2026-07-18T23:06:02.348167	{'source': 'webserver', 'gh_type': 'pull_request_review_comment', 'raw': {'action': 'created', 'comment': {'url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/comments/3609363364', 'pull_request_review_id': 4729447426, 'id': 3609363364, 'node_id': 'PRRC_kwDOALCn2M7XIoOk', 'diff_hunk': '@@ -186,7 +380,304 @@ std::unique_ptr<WbfsFileReader> WbfsFileReader::Create(File::DirectIOFile file,\n   if (!reader->IsGood())\n     reader.reset();\n \n+  if (reader && reader->m_has_nkit_header)\n+    reader->ReadPartitionInfo();\n+\n   return reader;\n }\n \n+// Converts any disc image to WBFS with an NKit v2 header for lossless round-trips.\n+// Strips disc-level junk and partition-level junk (encrypted sectors whose decrypted\n+// content is zero or LFG padding), records a junk bitmap for reconstruction.\n+// See: https://github.com/dolphin-emu/dolphin/pull/14731\n+bool ConvertToWBFS(BlobReader* infile, const std::string& infile_path,\n+                   const std::string& outfile_path, const CompressCB& callback)\n+{\n+  ASSERT(infile->GetDataSizeType() == DataSizeType::Accurate ||\n+         infile->GetDataSizeType() == DataSizeType::UpperBound);\n+\n+  File::DirectIOFile outfile(outfile_path, File::AccessMode::Write);\n+  if (!outfile.IsOpen())\n+  {\n+    PanicAlertFmtT(\n+        "Failed to open the output file \\"{0}\\".\\n"\n+        "Check that you have permissions to write the target folder and that the media can "\n+        "be written.",\n+        outfile_path);\n+    return false;\n+  }\n+\n+  const u64 disc_size = infile->GetDataSize();\n+\n+  // These match the values used by standard WBFS tools (wwt, WBFS Manager)\n+  static constexpr u8 hd_sector_shift = 9;\n+  static constexpr u8 wbfs_sector_shift = 21;\n+  static constexpr u64 hd_sector_size = 1ull << hd_sector_shift;\n+  static constexpr u64 wbfs_sector_size = 1ull << wbfs_sector_shift;\n+\n+  const u64 blocks_per_disc = (disc_size + wbfs_sector_size - 1) / wbfs_sector_size;\n+  const u64 disc_info_size =\n+      Common::AlignUp(WII_DISC_HEADER_SIZE + blocks_per_disc * sizeof(u16), hd_sector_size);\n+\n+  // Read disc header (first 256 bytes contain disc_id, disc_num, title, etc.)\n+  std::vector<u8> disc_header(WII_DISC_HEADER_SIZE, 0);\n+  if (!infile->Read(0, WII_DISC_HEADER_SIZE, disc_header.data()))\n+  {\n+    PanicAlertFmtT("Failed to read from the input file \\"{0}\\".", infile_path);\n+    return false;\n+  }\n+\n+  // Use Volume for partition info and decrypted reads\n+  struct PartitionInfo\n+  {\n+    u64 data_offset;\n+    u64 data_size;\n+    Partition partition;\n+  };\n+  std::vector<PartitionInfo> partitions;\n+\n+  std::unique_ptr<VolumeDisc> volume = CreateDisc(infile_path);\n+  if (volume)\n+  {\n+    for (const Partition& partition : volume->GetPartitions())\n+    {\n+      const std::optional<u64> data_offset =\n+          volume->ReadSwappedAndShifted(partition.offset + 0x2B8, PARTITION_NONE);\n+      const std::optional<u64> data_size =\n+          volume->ReadSwappedAndShifted(partition.offset + 0x2BC, PARTITION_NONE);\n+      if (!data_offset || !data_size)\n+        continue;\n+\n+      PartitionInfo info;\n+      info.data_offset = partition.offset + *data_offset;\n+      info.data_size = *data_size;\n+      info.partition = partition;\n+      partitions.push_back(info);\n+    }\n+  }\n+\n+  // NKit v2 gap type bitmap: 1 bit per block, MSB-first, always sized for dual-layer\n+  const u64 gap_type_blocks = (DL_DVD_SIZE + wbfs_sector_size - 1) / wbfs_sector_size;\n+  const u64 gap_type_bytes = (gap_type_blocks + 7) / 8;\n+  std::vector<u8> gap_type(gap_type_bytes, 0);\n+\n+  // Compute data_start up front so we can write sectors during the scan\n+  const u64 data_start = Common::AlignUp(hd_sector_size + disc_info_size, wbfs_sector_size);\n+  const u16 wlba_base = static_cast<u16>(data_start / wbfs_sector_size);\n+\n+  // Single pass: scan, classify, hash, and write used sectors in one loop\n+  std::vector<u8> sector_buf(wbfs_sector_size, 0);\n+  std::vector<u16> wlba_table(blocks_per_disc, 0);\n+  u16 used_count = 0;\n+\n+  // NKit v2 stores four hash digests for verification\n+  auto sha1_ctx = Common::SHA1::CreateContext();\n+  u32 crc = Common::StartCRC32();\n+  mbedtls_md5_context md5_ctx{};\n+  mbedtls_md5_init(&md5_ctx);\n+  mbedtls_md5_starts_ret(&md5_ctx);\n+  XXH64_state_t* xxh_state = XXH64_createState();\n+  XXH64_reset(xxh_state, 0);\n+\n+  for (u64 i = 0; i < blocks_per_disc; i++)\n+  {\n+    if (i % 100 == 0)\n+    {\n+      const bool was_cancelled =\n+          !callback(Common::GetStringT("Converting"),\n+                    static_cast<float>(i) / static_cast<float>(blocks_per_disc));\n+      if (was_cancelled)\n+      {\n+        XXH64_freeState(xxh_state);\n+        mbedtls_md5_free(&md5_ctx);\n+        outfile.Close();\n+        File::Delete(outfile_path);\n+        return false;\n+      }\n+    }\n+\n+    const u64 offset = i * wbfs_sector_size;\n+    const size_t sz = static_cast<size_t>(std::min(wbfs_sector_size, disc_size - offset));\n+\n+    if (!infile->Read(offset, sz, sector_buf.data()))\n+    {\n+      PanicAlertFmtT("Failed to read from the input file \\"{0}\\".", infile_path);\n+      XXH64_freeState(xxh_state);\n+      mbedtls_md5_free(&md5_ctx);\n+      outfile.Close();\n+      File::Delete(outfile_path);\n+      return false;\n+    }\n+\n+    // Update all four hashes with the full disc data\n+    sha1_ctx->Update(sector_buf.data(), sz);\n+    crc = Common::UpdateCRC32(crc, sector_buf.data(), sz);\n+    mbedtls_md5_update_ret(&md5_ctx, sector_buf.data(), sz);\n+    XXH64_update(xxh_state, sector_buf.data(), sz);\n+\n+    // Find which partition (if any) this block belongs to\n+    const u32 start_sector = static_cast<u32>(offset / VolumeWii::BLOCK_TOTAL_SIZE);\n+    const u32 end_sector = static_cast<u32>((offset + sz) / VolumeWii::BLOCK_TOTAL_SIZE);\n+    const auto it = std::ranges::find_if(partitions, [&](const PartitionInfo& p) {\n+      const u32 p_start = static_cast<u32>(p.data_offset / VolumeWii::BLOCK_TOTAL_SIZE);\n+      const u32 p_end =\n+          static_cast<u32>((p.data_offset + p.data_size) / VolumeWii::BLOCK_TOTAL_SIZE);', 'path': 'Source/Core/DiscIO/WbfsBlob.cpp', 'commit_id': '24b41d58df2315831b74f76b95417f2739d02f9d', 'original_commit_id': '24b41d58df2315831b74f76b95417f2739d02f9d', 'user': {'login': 'phire', 'id': 138484, 'node_id': 'MDQ6VXNlcjEzODQ4NA==', 'avatar_url': 'https://avatars.githubusercontent.com/u/138484?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/phire', 'html_url': 'https://github.com/phire', 'followers_url': 'https://api.github.com/users/phire/followers', 'following_url': 'https://api.github.com/users/phire/following{/other_user}', 'gists_url': 'https://api.github.com/users/phire/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/phire/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/phire/subscriptions', 'organizations_url': 'https://api.github.com/users/phire/orgs', 'repos_url': 'https://api.github.com/users/phire/repos', 'events_url': 'https://api.github.com/users/phire/events{/privacy}', 'received_events_url': 'https://api.github.com/users/phire/received_events', 'type': 'User', 'user_view_type': 'public', 'site_admin': False}, 'body': "Don't all these divisions cancel out? I think you can compare the offsets directly. ", 'created_at': '2026-07-18T23:05:59Z', 'updated_at': '2026-07-18T23:06:00Z', 'html_url': 'https://github.com/dolphin-emu/dolphin/pull/14731#discussion_r3609363364', 'pull_request_url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/14731', '_links': {'self': {'href': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/comments/3609363364'}, 'html': {'href': 'https://github.com/dolphin-emu/dolphin/pull/14731#discussion_r3609363364'}, 'pull_request': {'href': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/14731'}}, 'reactions': {'url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/comments/3609363364/reactions', 'total_count': 0, '+1': 0, '-1': 0, 'laugh': 0, 'hooray': 0, 'confused': 0, 'heart': 0, 'rocket': 0, 'eyes': 0}, 'start_line': 519, 'original_start_line': 519, 'start_side': 'RIGHT', 'line': 524, 'original_line': 524, 'side': 'RIGHT', 'author_association': 'MEMBER', 'original_position': 431, 'position': 431, 'subject_type': 'line'}, 'pull_request': {'url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/14731', 'id': 4056977334, 'node_id': 'PR_kwDOALCn2M7x0I-2', 'html_url': 'https://github.com/dolphin-emu/dolphin/pull/14731', 'diff_url': 'https://github.com/dolphin-emu/dolphin/pull/14731.diff', 'patch_url': 'https://github.com/dolphin-emu/dolphin/pull/14731.patch', 'issue_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/14731', 'number': 14731, 'state': 'open', 'locked': False, 'title': 'Convert To WBFS Support', 'user': {'login': 'thethiny', 'id': 6018214, 'node_id': 'MDQ6VXNlcjYwMTgyMTQ=', 'avatar_url': 'https://avatars.githubusercontent.com/u/6018214?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/thethiny', 'html_url': 'https://github.com/thethiny', 'followers_url': 'https://api.github.com/users/thethiny/followers', 'following_url': 'https://api.github.com/users/thethiny/following{/other_user}', 'gists_url': 'https://api.github.com/users/thethiny/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/thethiny/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/thethiny/subscriptions', 'organizations_url': 'https://api.github.com/users/thethiny/orgs', 'repos_url': 'https://api.github.com/users/thethiny/repos', 'events_url': 'https://api.github.com/users/thethiny/events{/privacy}', 'received_events_url': 'https://api.github.com/users/thethiny/received_events', 'type': 'User', 'user_view_type': 'public', 'site_admin': False}, 'body': "This PR introduces Conversion **to** WBFS support. WBFS is the format that is used by USB Loaders on a real Wii device.\r\n\r\n## Design decisions & hardcoded values\r\nThe writer uses fixed sector sizes that match what [libwbfs (the reference implementation by kwiirk)](https://github.com/kwiirk/wbfs/blob/master/libwbfs/libwbfs.c#L128-L134) computes for a standard single-layer Wii disc. These 2 hardcodes are stable and work correctly across all my testings.\r\n- HD sector shift: 9 (512 bytes)\r\n- WBFS sector shift: 21 (2 MiB)\r\nThese are not configurable via the UI. All existing WBFS tools use these values, and since the aim is to support USB Loaders then this has been tested and it is working on a real Wii.\r\n\r\nConverting from WBFS is not enabled. The existing `WbfsFileReader` reports `DataSizeType::UpperBound`, and `ShouldAllowConversion()` requires `Accurate`. I am able to support this but since it was hardcoded by the Dolphin team I thought a discussion is warranted.\r\n\r\n## Testing\r\n- Verified with DolphinTool header and DolphinTool verify\r\n- Verified with wit FILETYPE and wit DUMP (Wiimm's ISO Tools recognizes valid WBFS structure, partitions, encryption)\r\n- Tested ISO to WBFS and RVZ to WBFS conversions\r\n- Output file sizes match Wii Backup Manager when scrubbing is enabled (~0.1% difference), works when scrubbing is disabled.\r\n- Output WBFS files play correctly in Dolphin\r\n- Output WBFS files play correctly on a real Wii using USB Loader GX e25c4f3\r\n", 'created_at': '2026-07-15T01:16:25Z', 'updated_at': '2026-07-18T22:26:23Z', 'closed_at': None, 'merged_at': None, 'merge_commit_sha': '228f93416dd80eb09da834ad7852c8eaa4d9212b', 'assignees': [], 'requested_reviewers': [], 'requested_teams': [], 'labels': [], 'milestone': None, 'draft': False, 'commits_url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/14731/commits', 'review_comments_url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/14731/comments', 'review_comment_url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/comments{/number}', 'comments_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/14731/comments', 'statuses_url': 'https://api.github.com/repos/dolphin-emu/dolphin/statuses/24b41d58df2315831b74f76b95417f2739d02f9d', 'head': {'label': 'thethiny:wbfs-conversion', 'ref': 'wbfs-conversion', 'sha': '24b41d58df2315831b74f76b95417f2739d02f9d', 'user': {'login': 'thethiny', 'id': 6018214, 'node_id': 'MDQ6VXNlcjYwMTgyMTQ=', 'avatar_url': 'https://avatars.githubusercontent.com/u/6018214?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/thethiny', 'html_url': 'https://github.com/thethiny', 'followers_url': 'https://api.github.com/users/thethiny/followers', 'following_url': 'https://api.github.com/users/thethiny/following{/other_user}', 'gists_url': 'https://api.github.com/users/thethiny/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/thethiny/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/thethiny/subscriptions', 'organizations_url': 'https://api.github.com/users/thethiny/orgs', 'repos_url': 'https://api.github.com/users/thethiny/repos', 'events_url': 'https://api.github.com/users/thethiny/events{/privacy}', 'received_events_url': 'https://api.github.com/users/thethiny/received_events', 'type': 'User', 'user_view_type': 'public', 'site_admin': False}, 'repo': {'id': 1298654395, 'node_id': 'R_kgDOTWfkuw', 'name': 'dolphin', 'full_name': 'thethiny/dolphin', 'private': False, 'owner': {'login': 'thethiny', 'id': 6018214, 'node_id': 'MDQ6VXNlcjYwMTgyMTQ=', 'avatar_url': 'https://avatars.githubusercontent.com/u/6018214?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/thethiny', 'html_url': 'https://github.com/thethiny', 'followers_url': 'https://api.github.com/users/thethiny/followers', 'following_url': 'https://api.github.com/users/thethiny/following{/other_user}', 'gists_url': 'https://api.github.com/users/thethiny/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/thethiny/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/thethiny/subscriptions', 'organizations_url': 'https://api.github.com/users/thethiny/orgs', 'repos_url': 'https://api.github.com/users/thethiny/repos', 'events_url': 'https://api.github.com/users/thethiny/events{/privacy}', 'received_events_url': 'https://api.github.com/users/thethiny/received_events', 'type': 'User', 'user_view_type': 'public', 'site_admin': False}, 'html_url': 'https://github.com/thethiny/dolphin', 'description': 'Dolphin is a GameCube / Wii emulator, allowing you to play games for these two platforms on PC with improvements.', 'fork': True, 'url': 'https://api.github.com/repos/thethiny/dolphin', 'forks_url': 'https://api.github.com/repos/thethiny/dolphin/forks', 'keys_url': 'https://api.github.com/repos/thethiny/dolphin/keys{/key_id}', 'collaborators_url': 'https://api.github.com/repos/thethiny/dolphin/collaborators{/collaborator}', 'teams_url': 'https://api.github.com/repos/thethiny/dolphin/teams', 'hooks_url': 'https://api.github.com/repos/thethiny/dolphin/hooks', 'issue_events_url': 'https://api.github.com/repos/thethiny/dolphin/issues/events{/number}', 'events_url': 'https://api.github.com/repos/thethiny/dolphin/events', 'assignees_url': 'https://api.github.com/repos/thethiny/dolphin/assignees{/user}', 'branches_url': 'https://api.github.com/repos/thethiny/dolphin/branches{/branch}', 'tags_url': 'https://api.github.com/repos/thethiny/dolphin/tags', 'blobs_url': 'https://api.github.com/repos/thethiny/dolphin/git/blobs{/sha}', 'git_tags_url': 'https://api.github.com/repos/thethiny/dolphin/git/tags{/sha}', 'git_refs_url': 'https://api.github.com/repos/thethiny/dolphin/git/refs{/sha}', 'trees_url': 'https://api.github.com/repos/thethiny/dolphin/git/trees{/sha}', 'statuses_url': 'https://api.github.com/repos/thethiny/dolphin/statuses/{sha}', 'languages_url': 'https://api.github.com/repos/thethiny/dolphin/languages', 'stargazers_url': 'https://api.github.com/repos/thethiny/dolphin/stargazers', 'contributors_url': 'https://api.github.com/repos/thethiny/dolphin/contributors', 'subscribers_url': 'https://api.github.com/repos/thethiny/dolphin/subscribers', 'subscription_url': 'https://api.github.com/repos/thethiny/dolphin/subscription', 'commits_url': 'https://api.github.com/repos/thethiny/dolphin/commits{/sha}', 'git_commits_url': 'https://api.github.com/repos/thethiny/dolphin/git/commits{/sha}', 'comments_url': 'https://api.github.com/repos/thethiny/dolphin/comments{/number}', 'issue_comment_url': 'https://api.github.com/repos/thethiny/dolphin/issues/comments{/number}', 'contents_url': 'https://api.github.com/repos/thethiny/dolphin/contents/{+path}', 'compare_url': 'https://api.github.com/repos/thethiny/dolphin/compare/{base}...{head}', 'merges_url': 'https://api.github.com/repos/thethiny/dolphin/merges', 'archive_url': 'https://api.github.com/repos/thethiny/dolphin/{archive_format}{/ref}', 'downloads_url': 'https://api.github.com/repos/thethiny/dolphin/downloads', 'issues_url': 'https://api.github.com/repos/thethiny/dolphin/issues{/number}', 'pulls_url': 'https://api.github.com/repos/thethiny/dolphin/pulls{/number}', 'milestones_url': 'https://api.github.com/repos/thethiny/dolphin/milestones{/number}', 'notifications_url': 'https://api.github.com/repos/thethiny/dolphin/notifications{?since,all,participating}', 'labels_url': 'https://api.github.com/repos/thethiny/dolphin/labels{/name}', 'releases_url': 'https://api.github.com/repos/thethiny/dolphin/releases{/id}', 'deployments_url': 'https://api.github.com/repos/thethiny/dolphin/deployments', 'created_at': '2026-07-12T22:09:13Z', 'updated_at': '2026-07-12T22:09:13Z', 'pushed_at': '2026-07-18T20:35:03Z', 'git_url': 'git://github.com/thethiny/dolphin.git', 'ssh_url': 'git@github.com:thethiny/dolphin.git', 'clone_url': 'https://github.com/thethiny/dolphin.git', 'svn_url': 'https://github.com/thethiny/dolphin', 'homepage': 'https://dolphin-emu.org', 'size': 515471, 'stargazers_count': 0, 'watchers_count': 0, 'language': None, 'has_issues': False, 'has_projects': True, 'has_downloads': True, 'has_wiki': True, 'has_pages': False, 'has_discussions': False, 'forks_count': 0, 'mirror_url': None, 'archived': False, 'disabled': False, 'open_issues_count': 0, 'license': {'key': 'other', 'name': 'Other', 'spdx_id': 'NOASSERTION', 'url': None, 'node_id': 'MDc6TGljZW5zZTA='}, 'allow_forking': True, 'is_template': False, 'web_commit_signoff_required': False, 'has_pull_requests': True, 'pull_request_creation_policy': 'all', 'topics': [], 'visibility': 'public', 'forks': 0, 'open_issues': 0, 'watchers': 0, 'default_branch': 'master', 'allow_squash_merge': True, 'allow_merge_commit': True, 'allow_rebase_merge': True, 'allow_auto_merge': False, 'delete_branch_on_merge': False, 'allow_update_branch': False, 'use_squash_pr_title_as_default': False, 'squash_merge_commit_message': 'COMMIT_MESSAGES', 'squash_merge_commit_title': 'COMMIT_OR_PR_TITLE', 'merge_commit_message': 'PR_TITLE', 'merge_commit_title': 'MERGE_MESSAGE'}}, 'base': {'label': 'dolphin-emu:master', 'ref': 'master', 'sha': 'd3b2943807dd0073f7767947466dd73cccfef319', 'user': {'login': 'dolphin-emu', 'id': 5050316, 'node_id': 'MDEyOk9yZ2FuaXphdGlvbjUwNTAzMTY=', 'avatar_url': 'https://avatars.githubusercontent.com/u/5050316?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/dolphin-emu', 'html_url': 'https://github.com/dolphin-emu', 'followers_url': 'https://api.github.com/users/dolphin-emu/followers', 'following_url': 'https://api.github.com/users/dolphin-emu/following{/other_user}', 'gists_url': 'https://api.github.com/users/dolphin-emu/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/dolphin-emu/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/dolphin-emu/subscriptions', 'organizations_url': 'https://api.github.com/users/dolphin-emu/orgs', 'repos_url': 'https://api.github.com/users/dolphin-emu/repos', 'events_url': 'https://api.github.com/users/dolphin-emu/events{/privacy}', 'received_events_url': 'https://api.github.com/users/dolphin-emu/received_events', 'type': 'Organization', 'user_view_type': 'public', 'site_admin': False}, 'repo': {'id': 11577304, 'node_id': 'MDEwOlJlcG9zaXRvcnkxMTU3NzMwNA==', 'name': 'dolphin', 'full_name': 'dolphin-emu/dolphin', 'private': False, 'owner': {'login': 'dolphin-emu', 'id': 5050316, 'node_id': 'MDEyOk9yZ2FuaXphdGlvbjUwNTAzMTY=', 'avatar_url': 'https://avatars.githubusercontent.com/u/5050316?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/dolphin-emu', 'html_url': 'https://github.com/dolphin-emu', 'followers_url': 'https://api.github.com/users/dolphin-emu/followers', 'following_url': 'https://api.github.com/users/dolphin-emu/following{/other_user}', 'gists_url': 'https://api.github.com/users/dolphin-emu/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/dolphin-emu/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/dolphin-emu/subscriptions', 'organizations_url': 'https://api.github.com/users/dolphin-emu/orgs', 'repos_url': 'https://api.github.com/users/dolphin-emu/repos', 'events_url': 'https://api.github.com/users/dolphin-emu/events{/privacy}', 'received_events_url': 'https://api.github.com/users/dolphin-emu/received_events', 'type': 'Organization', 'user_view_type': 'public', 'site_admin': False}, 'html_url': 'https://github.com/dolphin-emu/dolphin', 'description': 'Dolphin is a GameCube / Wii emulator, allowing you to play games for these two platforms on PC with improvements.', 'fork': False, 'url': 'https://api.github.com/repos/dolphin-emu/dolphin', 'forks_url': 'https://api.github.com/repos/dolphin-emu/dolphin/forks', 'keys_url': 'https://api.github.com/repos/dolphin-emu/dolphin/keys{/key_id}', 'collaborators_url': 'https://api.github.com/repos/dolphin-emu/dolphin/collaborators{/collaborator}', 'teams_url': 'https://api.github.com/repos/dolphin-emu/dolphin/teams', 'hooks_url': 'https://api.github.com/repos/dolphin-emu/dolphin/hooks', 'issue_events_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/events{/number}', 'events_url': 'https://api.github.com/repos/dolphin-emu/dolphin/events', 'assignees_url': 'https://api.github.com/repos/dolphin-emu/dolphin/assignees{/user}', 'branches_url': 'https://api.github.com/repos/dolphin-emu/dolphin/branches{/branch}', 'tags_url': 'https://api.github.com/repos/dolphin-emu/dolphin/tags', 'blobs_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/blobs{/sha}', 'git_tags_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/tags{/sha}', 'git_refs_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/refs{/sha}', 'trees_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/trees{/sha}', 'statuses_url': 'https://api.github.com/repos/dolphin-emu/dolphin/statuses/{sha}', 'languages_url': 'https://api.github.com/repos/dolphin-emu/dolphin/languages', 'stargazers_url': 'https://api.github.com/repos/dolphin-emu/dolphin/stargazers', 'contributors_url': 'https://api.github.com/repos/dolphin-emu/dolphin/contributors', 'subscribers_url': 'https://api.github.com/repos/dolphin-emu/dolphin/subscribers', 'subscription_url': 'https://api.github.com/repos/dolphin-emu/dolphin/subscription', 'commits_url': 'https://api.github.com/repos/dolphin-emu/dolphin/commits{/sha}', 'git_commits_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/commits{/sha}', 'comments_url': 'https://api.github.com/repos/dolphin-emu/dolphin/comments{/number}', 'issue_comment_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/comments{/number}', 'contents_url': 'https://api.github.com/repos/dolphin-emu/dolphin/contents/{+path}', 'compare_url': 'https://api.github.com/repos/dolphin-emu/dolphin/compare/{base}...{head}', 'merges_url': 'https://api.github.com/repos/dolphin-emu/dolphin/merges', 'archive_url': 'https://api.github.com/repos/dolphin-emu/dolphin/{archive_format}{/ref}', 'downloads_url': 'https://api.github.com/repos/dolphin-emu/dolphin/downloads', 'issues_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues{/number}', 'pulls_url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls{/number}', 'milestones_url': 'https://api.github.com/repos/dolphin-emu/dolphin/milestones{/number}', 'notifications_url': 'https://api.github.com/repos/dolphin-emu/dolphin/notifications{?since,all,participating}', 'labels_url': 'https://api.github.com/repos/dolphin-emu/dolphin/labels{/name}', 'releases_url': 'https://api.github.com/repos/dolphin-emu/dolphin/releases{/id}', 'deployments_url': 'https://api.github.com/repos/dolphin-emu/dolphin/deployments', 'created_at': '2013-07-22T09:07:57Z', 'updated_at': '2026-07-18T18:44:16Z', 'pushed_at': '2026-07-18T10:34:54Z', 'git_url': 'git://github.com/dolphin-emu/dolphin.git', 'ssh_url': 'git@github.com:dolphin-emu/dolphin.git', 'clone_url': 'https://github.com/dolphin-emu/dolphin.git', 'svn_url': 'https://github.com/dolphin-emu/dolphin', 'homepage': 'https://dolphin-emu.org', 'size': 558448, 'stargazers_count': 15272, 'watchers_count': 15272, 'language': 'C++', 'has_issues': False, 'has_projects': False, 'has_downloads': True, 'has_wiki': True, 'has_pages': False, 'has_discussions': False, 'forks_count': 3162, 'mirror_url': None, 'archived': False, 'disabled': False, 'open_issues_count': 446, 'license': {'key': 'other', 'name': 'Other', 'spdx_id': 'NOASSERTION', 'url': None, 'node_id': 'MDc6TGljZW5zZTA='}, 'allow_forking': True, 'is_template': False, 'web_commit_signoff_required': False, 'has_pull_requests': True, 'pull_request_creation_policy': 'all', 'topics': ['cpp', 'emulation', 'emulator', 'gamecube', 'wii'], 'visibility': 'public', 'forks': 3162, 'open_issues': 446, 'watchers': 15272, 'default_branch': 'master', 'allow_squash_merge': False, 'allow_merge_commit': True, 'allow_rebase_merge': False, 'allow_auto_merge': False, 'delete_branch_on_merge': False, 'allow_update_branch': False, 'use_squash_pr_title_as_default': False, 'squash_merge_commit_message': 'COMMIT_MESSAGES', 'squash_merge_commit_title': 'COMMIT_OR_PR_TITLE', 'merge_commit_message': 'PR_TITLE', 'merge_commit_title': 'MERGE_MESSAGE'}}, '_links': {'self': {'href': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/14731'}, 'html': {'href': 'https://github.com/dolphin-emu/dolphin/pull/14731'}, 'issue': {'href': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/14731'}, 'comments': {'href': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/14731/comments'}, 'review_comments': {'href': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/14731/comments'}, 'review_comment': {'href': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/comments{/number}'}, 'commits': {'href': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/14731/commits'}, 'statuses': {'href': 'https://api.github.com/repos/dolphin-emu/dolphin/statuses/24b41d58df2315831b74f76b95417f2739d02f9d'}}, 'author_association': 'NONE', 'auto_merge': None, 'assignee': None, 'active_lock_reason': None}, 'repository': {'id': 11577304, 'node_id': 'MDEwOlJlcG9zaXRvcnkxMTU3NzMwNA==', 'name': 'dolphin', 'full_name': 'dolphin-emu/dolphin', 'private': False, 'owner': {'login': 'dolphin-emu', 'id': 5050316, 'node_id': 'MDEyOk9yZ2FuaXphdGlvbjUwNTAzMTY=', 'avatar_url': 'https://avatars.githubusercontent.com/u/5050316?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/dolphin-emu', 'html_url': 'https://github.com/dolphin-emu', 'followers_url': 'https://api.github.com/users/dolphin-emu/followers', 'following_url': 'https://api.github.com/users/dolphin-emu/following{/other_user}', 'gists_url': 'https://api.github.com/users/dolphin-emu/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/dolphin-emu/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/dolphin-emu/subscriptions', 'organizations_url': 'https://api.github.com/users/dolphin-emu/orgs', 'repos_url': 'https://api.github.com/users/dolphin-emu/repos', 'events_url': 'https://api.github.com/users/dolphin-emu/events{/privacy}', 'received_events_url': 'https://api.github.com/users/dolphin-emu/received_events', 'type': 'Organization', 'user_view_type': 'public', 'site_admin': False}, 'html_url': 'https://github.com/dolphin-emu/dolphin', 'description': 'Dolphin is a GameCube / Wii emulator, allowing you to play games for these two platforms on PC with improvements.', 'fork': False, 'url': 'https://api.github.com/repos/dolphin-emu/dolphin', 'forks_url': 'https://api.github.com/repos/dolphin-emu/dolphin/forks', 'keys_url': 'https://api.github.com/repos/dolphin-emu/dolphin/keys{/key_id}', 'collaborators_url': 'https://api.github.com/repos/dolphin-emu/dolphin/collaborators{/collaborator}', 'teams_url': 'https://api.github.com/repos/dolphin-emu/dolphin/teams', 'hooks_url': 'https://api.github.com/repos/dolphin-emu/dolphin/hooks', 'issue_events_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/events{/number}', 'events_url': 'https://api.github.com/repos/dolphin-emu/dolphin/events', 'assignees_url': 'https://api.github.com/repos/dolphin-emu/dolphin/assignees{/user}', 'branches_url': 'https://api.github.com/repos/dolphin-emu/dolphin/branches{/branch}', 'tags_url': 'https://api.github.com/repos/dolphin-emu/dolphin/tags', 'blobs_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/blobs{/sha}', 'git_tags_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/tags{/sha}', 'git_refs_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/refs{/sha}', 'trees_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/trees{/sha}', 'statuses_url': 'https://api.github.com/repos/dolphin-emu/dolphin/statuses/{sha}', 'languages_url': 'https://api.github.com/repos/dolphin-emu/dolphin/languages', 'stargazers_url': 'https://api.github.com/repos/dolphin-emu/dolphin/stargazers', 'contributors_url': 'https://api.github.com/repos/dolphin-emu/dolphin/contributors', 'subscribers_url': 'https://api.github.com/repos/dolphin-emu/dolphin/subscribers', 'subscription_url': 'https://api.github.com/repos/dolphin-emu/dolphin/subscription', 'commits_url': 'https://api.github.com/repos/dolphin-emu/dolphin/commits{/sha}', 'git_commits_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/commits{/sha}', 'comments_url': 'https://api.github.com/repos/dolphin-emu/dolphin/comments{/number}', 'issue_comment_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/comments{/number}', 'contents_url': 'https://api.github.com/repos/dolphin-emu/dolphin/contents/{+path}', 'compare_url': 'https://api.github.com/repos/dolphin-emu/dolphin/compare/{base}...{head}', 'merges_url': 'https://api.github.com/repos/dolphin-emu/dolphin/merges', 'archive_url': 'https://api.github.com/repos/dolphin-emu/dolphin/{archive_format}{/ref}', 'downloads_url': 'https://api.github.com/repos/dolphin-emu/dolphin/downloads', 'issues_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues{/number}', 'pulls_url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls{/number}', 'milestones_url': 'https://api.github.com/repos/dolphin-emu/dolphin/milestones{/number}', 'notifications_url': 'https://api.github.com/repos/dolphin-emu/dolphin/notifications{?since,all,participating}', 'labels_url': 'https://api.github.com/repos/dolphin-emu/dolphin/labels{/name}', 'releases_url': 'https://api.github.com/repos/dolphin-emu/dolphin/releases{/id}', 'deployments_url': 'https://api.github.com/repos/dolphin-emu/dolphin/deployments', 'created_at': '2013-07-22T09:07:57Z', 'updated_at': '2026-07-18T18:44:16Z', 'pushed_at': '2026-07-18T10:34:54Z', 'git_url': 'git://github.com/dolphin-emu/dolphin.git', 'ssh_url': 'git@github.com:dolphin-emu/dolphin.git', 'clone_url': 'https://github.com/dolphin-emu/dolphin.git', 'svn_url': 'https://github.com/dolphin-emu/dolphin', 'homepage': 'https://dolphin-emu.org', 'size': 558448, 'stargazers_count': 15272, 'watchers_count': 15272, 'language': 'C++', 'has_issues': False, 'has_projects': False, 'has_downloads': True, 'has_wiki': True, 'has_pages': False, 'has_discussions': False, 'forks_count': 3162, 'mirror_url': None, 'archived': False, 'disabled': False, 'open_issues_count': 446, 'license': {'key': 'other', 'name': 'Other', 'spdx_id': 'NOASSERTION', 'url': None, 'node_id': 'MDc6TGljZW5zZTA='}, 'allow_forking': True, 'is_template': False, 'web_commit_signoff_required': False, 'has_pull_requests': True, 'pull_request_creation_policy': 'all', 'topics': ['cpp', 'emulation', 'emulator', 'gamecube', 'wii'], 'visibility': 'public', 'forks': 3162, 'open_issues': 446, 'watchers': 15272, 'default_branch': 'master', 'custom_properties': {}}, 'organization': {'login': 'dolphin-emu', 'id': 5050316, 'node_id': 'MDEyOk9yZ2FuaXphdGlvbjUwNTAzMTY=', 'url': 'https://api.github.com/orgs/dolphin-emu', 'repos_url': 'https://api.github.com/orgs/dolphin-emu/repos', 'events_url': 'https://api.github.com/orgs/dolphin-emu/events', 'hooks_url': 'https://api.github.com/orgs/dolphin-emu/hooks', 'issues_url': 'https://api.github.com/orgs/dolphin-emu/issues', 'members_url': 'https://api.github.com/orgs/dolphin-emu/members{/member}', 'public_members_url': 'https://api.github.com/orgs/dolphin-emu/public_members{/member}', 'avatar_url': 'https://avatars.githubusercontent.com/u/5050316?v=4', 'description': ''}, 'sender': {'login': 'phire', 'id': 138484, 'node_id': 'MDQ6VXNlcjEzODQ4NA==', 'avatar_url': 'https://avatars.githubusercontent.com/u/138484?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/phire', 'html_url': 'https://github.com/phire', 'followers_url': 'https://api.github.com/users/phire/followers', 'following_url': 'https://api.github.com/users/phire/following{/other_user}', 'gists_url': 'https://api.github.com/users/phire/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/phire/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/phire/subscriptions', 'organizations_url': 'https://api.github.com/users/phire/orgs', 'repos_url': 'https://api.github.com/users/phire/repos', 'events_url': 'https://api.github.com/users/phire/events{/privacy}', 'received_events_url': 'https://api.github.com/users/phire/received_events', 'type': 'User', 'user_view_type': 'public', 'site_admin': False}, 'installation': {'id': 35437981, 'node_id': 'MDIzOkludGVncmF0aW9uSW5zdGFsbGF0aW9uMzU0Mzc5ODE='}}, 'type': 'raw_gh_hook'}
2026-07-18T23:06:02.346528	{'source': 'webserver', 'gh_type': 'pull_request_review', 'raw': {'action': 'submitted', 'review': {'id': 4729447426, 'node_id': 'PRR_kwDOALCn2M8AAAABGeWkAg', 'user': {'login': 'phire', 'id': 138484, 'node_id': 'MDQ6VXNlcjEzODQ4NA==', 'avatar_url': 'https://avatars.githubusercontent.com/u/138484?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/phire', 'html_url': 'https://github.com/phire', 'followers_url': 'https://api.github.com/users/phire/followers', 'following_url': 'https://api.github.com/users/phire/following{/other_user}', 'gists_url': 'https://api.github.com/users/phire/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/phire/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/phire/subscriptions', 'organizations_url': 'https://api.github.com/users/phire/orgs', 'repos_url': 'https://api.github.com/users/phire/repos', 'events_url': 'https://api.github.com/users/phire/events{/privacy}', 'received_events_url': 'https://api.github.com/users/phire/received_events', 'type': 'User', 'user_view_type': 'public', 'site_admin': False}, 'body': None, 'commit_id': '24b41d58df2315831b74f76b95417f2739d02f9d', 'state': 'commented', 'html_url': 'https://github.com/dolphin-emu/dolphin/pull/14731#pullrequestreview-4729447426', 'pull_request_url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/14731', '_links': {'html': {'href': 'https://github.com/dolphin-emu/dolphin/pull/14731#pullrequestreview-4729447426'}, 'pull_request': {'href': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/14731'}}, 'submitted_at': '2026-07-18T23:05:59Z', 'updated_at': '2026-07-18T23:06:00Z', 'author_association': 'MEMBER'}, 'pull_request': {'url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/14731', 'id': 4056977334, 'node_id': 'PR_kwDOALCn2M7x0I-2', 'html_url': 'https://github.com/dolphin-emu/dolphin/pull/14731', 'diff_url': 'https://github.com/dolphin-emu/dolphin/pull/14731.diff', 'patch_url': 'https://github.com/dolphin-emu/dolphin/pull/14731.patch', 'issue_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/14731', 'number': 14731, 'state': 'open', 'locked': False, 'title': 'Convert To WBFS Support', 'user': {'login': 'thethiny', 'id': 6018214, 'node_id': 'MDQ6VXNlcjYwMTgyMTQ=', 'avatar_url': 'https://avatars.githubusercontent.com/u/6018214?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/thethiny', 'html_url': 'https://github.com/thethiny', 'followers_url': 'https://api.github.com/users/thethiny/followers', 'following_url': 'https://api.github.com/users/thethiny/following{/other_user}', 'gists_url': 'https://api.github.com/users/thethiny/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/thethiny/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/thethiny/subscriptions', 'organizations_url': 'https://api.github.com/users/thethiny/orgs', 'repos_url': 'https://api.github.com/users/thethiny/repos', 'events_url': 'https://api.github.com/users/thethiny/events{/privacy}', 'received_events_url': 'https://api.github.com/users/thethiny/received_events', 'type': 'User', 'user_view_type': 'public', 'site_admin': False}, 'body': "This PR introduces Conversion **to** WBFS support. WBFS is the format that is used by USB Loaders on a real Wii device.\r\n\r\n## Design decisions & hardcoded values\r\nThe writer uses fixed sector sizes that match what [libwbfs (the reference implementation by kwiirk)](https://github.com/kwiirk/wbfs/blob/master/libwbfs/libwbfs.c#L128-L134) computes for a standard single-layer Wii disc. These 2 hardcodes are stable and work correctly across all my testings.\r\n- HD sector shift: 9 (512 bytes)\r\n- WBFS sector shift: 21 (2 MiB)\r\nThese are not configurable via the UI. All existing WBFS tools use these values, and since the aim is to support USB Loaders then this has been tested and it is working on a real Wii.\r\n\r\nConverting from WBFS is not enabled. The existing `WbfsFileReader` reports `DataSizeType::UpperBound`, and `ShouldAllowConversion()` requires `Accurate`. I am able to support this but since it was hardcoded by the Dolphin team I thought a discussion is warranted.\r\n\r\n## Testing\r\n- Verified with DolphinTool header and DolphinTool verify\r\n- Verified with wit FILETYPE and wit DUMP (Wiimm's ISO Tools recognizes valid WBFS structure, partitions, encryption)\r\n- Tested ISO to WBFS and RVZ to WBFS conversions\r\n- Output file sizes match Wii Backup Manager when scrubbing is enabled (~0.1% difference), works when scrubbing is disabled.\r\n- Output WBFS files play correctly in Dolphin\r\n- Output WBFS files play correctly on a real Wii using USB Loader GX e25c4f3\r\n", 'created_at': '2026-07-15T01:16:25Z', 'updated_at': '2026-07-18T22:26:23Z', 'closed_at': None, 'merged_at': None, 'merge_commit_sha': '228f93416dd80eb09da834ad7852c8eaa4d9212b', 'assignees': [], 'requested_reviewers': [], 'requested_teams': [], 'labels': [], 'milestone': None, 'draft': False, 'commits_url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/14731/commits', 'review_comments_url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/14731/comments', 'review_comment_url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/comments{/number}', 'comments_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/14731/comments', 'statuses_url': 'https://api.github.com/repos/dolphin-emu/dolphin/statuses/24b41d58df2315831b74f76b95417f2739d02f9d', 'head': {'label': 'thethiny:wbfs-conversion', 'ref': 'wbfs-conversion', 'sha': '24b41d58df2315831b74f76b95417f2739d02f9d', 'user': {'login': 'thethiny', 'id': 6018214, 'node_id': 'MDQ6VXNlcjYwMTgyMTQ=', 'avatar_url': 'https://avatars.githubusercontent.com/u/6018214?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/thethiny', 'html_url': 'https://github.com/thethiny', 'followers_url': 'https://api.github.com/users/thethiny/followers', 'following_url': 'https://api.github.com/users/thethiny/following{/other_user}', 'gists_url': 'https://api.github.com/users/thethiny/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/thethiny/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/thethiny/subscriptions', 'organizations_url': 'https://api.github.com/users/thethiny/orgs', 'repos_url': 'https://api.github.com/users/thethiny/repos', 'events_url': 'https://api.github.com/users/thethiny/events{/privacy}', 'received_events_url': 'https://api.github.com/users/thethiny/received_events', 'type': 'User', 'user_view_type': 'public', 'site_admin': False}, 'repo': {'id': 1298654395, 'node_id': 'R_kgDOTWfkuw', 'name': 'dolphin', 'full_name': 'thethiny/dolphin', 'private': False, 'owner': {'login': 'thethiny', 'id': 6018214, 'node_id': 'MDQ6VXNlcjYwMTgyMTQ=', 'avatar_url': 'https://avatars.githubusercontent.com/u/6018214?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/thethiny', 'html_url': 'https://github.com/thethiny', 'followers_url': 'https://api.github.com/users/thethiny/followers', 'following_url': 'https://api.github.com/users/thethiny/following{/other_user}', 'gists_url': 'https://api.github.com/users/thethiny/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/thethiny/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/thethiny/subscriptions', 'organizations_url': 'https://api.github.com/users/thethiny/orgs', 'repos_url': 'https://api.github.com/users/thethiny/repos', 'events_url': 'https://api.github.com/users/thethiny/events{/privacy}', 'received_events_url': 'https://api.github.com/users/thethiny/received_events', 'type': 'User', 'user_view_type': 'public', 'site_admin': False}, 'html_url': 'https://github.com/thethiny/dolphin', 'description': 'Dolphin is a GameCube / Wii emulator, allowing you to play games for these two platforms on PC with improvements.', 'fork': True, 'url': 'https://api.github.com/repos/thethiny/dolphin', 'forks_url': 'https://api.github.com/repos/thethiny/dolphin/forks', 'keys_url': 'https://api.github.com/repos/thethiny/dolphin/keys{/key_id}', 'collaborators_url': 'https://api.github.com/repos/thethiny/dolphin/collaborators{/collaborator}', 'teams_url': 'https://api.github.com/repos/thethiny/dolphin/teams', 'hooks_url': 'https://api.github.com/repos/thethiny/dolphin/hooks', 'issue_events_url': 'https://api.github.com/repos/thethiny/dolphin/issues/events{/number}', 'events_url': 'https://api.github.com/repos/thethiny/dolphin/events', 'assignees_url': 'https://api.github.com/repos/thethiny/dolphin/assignees{/user}', 'branches_url': 'https://api.github.com/repos/thethiny/dolphin/branches{/branch}', 'tags_url': 'https://api.github.com/repos/thethiny/dolphin/tags', 'blobs_url': 'https://api.github.com/repos/thethiny/dolphin/git/blobs{/sha}', 'git_tags_url': 'https://api.github.com/repos/thethiny/dolphin/git/tags{/sha}', 'git_refs_url': 'https://api.github.com/repos/thethiny/dolphin/git/refs{/sha}', 'trees_url': 'https://api.github.com/repos/thethiny/dolphin/git/trees{/sha}', 'statuses_url': 'https://api.github.com/repos/thethiny/dolphin/statuses/{sha}', 'languages_url': 'https://api.github.com/repos/thethiny/dolphin/languages', 'stargazers_url': 'https://api.github.com/repos/thethiny/dolphin/stargazers', 'contributors_url': 'https://api.github.com/repos/thethiny/dolphin/contributors', 'subscribers_url': 'https://api.github.com/repos/thethiny/dolphin/subscribers', 'subscription_url': 'https://api.github.com/repos/thethiny/dolphin/subscription', 'commits_url': 'https://api.github.com/repos/thethiny/dolphin/commits{/sha}', 'git_commits_url': 'https://api.github.com/repos/thethiny/dolphin/git/commits{/sha}', 'comments_url': 'https://api.github.com/repos/thethiny/dolphin/comments{/number}', 'issue_comment_url': 'https://api.github.com/repos/thethiny/dolphin/issues/comments{/number}', 'contents_url': 'https://api.github.com/repos/thethiny/dolphin/contents/{+path}', 'compare_url': 'https://api.github.com/repos/thethiny/dolphin/compare/{base}...{head}', 'merges_url': 'https://api.github.com/repos/thethiny/dolphin/merges', 'archive_url': 'https://api.github.com/repos/thethiny/dolphin/{archive_format}{/ref}', 'downloads_url': 'https://api.github.com/repos/thethiny/dolphin/downloads', 'issues_url': 'https://api.github.com/repos/thethiny/dolphin/issues{/number}', 'pulls_url': 'https://api.github.com/repos/thethiny/dolphin/pulls{/number}', 'milestones_url': 'https://api.github.com/repos/thethiny/dolphin/milestones{/number}', 'notifications_url': 'https://api.github.com/repos/thethiny/dolphin/notifications{?since,all,participating}', 'labels_url': 'https://api.github.com/repos/thethiny/dolphin/labels{/name}', 'releases_url': 'https://api.github.com/repos/thethiny/dolphin/releases{/id}', 'deployments_url': 'https://api.github.com/repos/thethiny/dolphin/deployments', 'created_at': '2026-07-12T22:09:13Z', 'updated_at': '2026-07-12T22:09:13Z', 'pushed_at': '2026-07-18T20:35:03Z', 'git_url': 'git://github.com/thethiny/dolphin.git', 'ssh_url': 'git@github.com:thethiny/dolphin.git', 'clone_url': 'https://github.com/thethiny/dolphin.git', 'svn_url': 'https://github.com/thethiny/dolphin', 'homepage': 'https://dolphin-emu.org', 'size': 515471, 'stargazers_count': 0, 'watchers_count': 0, 'language': None, 'has_issues': False, 'has_projects': True, 'has_downloads': True, 'has_wiki': True, 'has_pages': False, 'has_discussions': False, 'forks_count': 0, 'mirror_url': None, 'archived': False, 'disabled': False, 'open_issues_count': 0, 'license': {'key': 'other', 'name': 'Other', 'spdx_id': 'NOASSERTION', 'url': None, 'node_id': 'MDc6TGljZW5zZTA='}, 'allow_forking': True, 'is_template': False, 'web_commit_signoff_required': False, 'has_pull_requests': True, 'pull_request_creation_policy': 'all', 'topics': [], 'visibility': 'public', 'forks': 0, 'open_issues': 0, 'watchers': 0, 'default_branch': 'master', 'allow_squash_merge': True, 'allow_merge_commit': True, 'allow_rebase_merge': True, 'allow_auto_merge': False, 'delete_branch_on_merge': False, 'allow_update_branch': False, 'use_squash_pr_title_as_default': False, 'squash_merge_commit_message': 'COMMIT_MESSAGES', 'squash_merge_commit_title': 'COMMIT_OR_PR_TITLE', 'merge_commit_message': 'PR_TITLE', 'merge_commit_title': 'MERGE_MESSAGE'}}, 'base': {'label': 'dolphin-emu:master', 'ref': 'master', 'sha': 'd3b2943807dd0073f7767947466dd73cccfef319', 'user': {'login': 'dolphin-emu', 'id': 5050316, 'node_id': 'MDEyOk9yZ2FuaXphdGlvbjUwNTAzMTY=', 'avatar_url': 'https://avatars.githubusercontent.com/u/5050316?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/dolphin-emu', 'html_url': 'https://github.com/dolphin-emu', 'followers_url': 'https://api.github.com/users/dolphin-emu/followers', 'following_url': 'https://api.github.com/users/dolphin-emu/following{/other_user}', 'gists_url': 'https://api.github.com/users/dolphin-emu/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/dolphin-emu/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/dolphin-emu/subscriptions', 'organizations_url': 'https://api.github.com/users/dolphin-emu/orgs', 'repos_url': 'https://api.github.com/users/dolphin-emu/repos', 'events_url': 'https://api.github.com/users/dolphin-emu/events{/privacy}', 'received_events_url': 'https://api.github.com/users/dolphin-emu/received_events', 'type': 'Organization', 'user_view_type': 'public', 'site_admin': False}, 'repo': {'id': 11577304, 'node_id': 'MDEwOlJlcG9zaXRvcnkxMTU3NzMwNA==', 'name': 'dolphin', 'full_name': 'dolphin-emu/dolphin', 'private': False, 'owner': {'login': 'dolphin-emu', 'id': 5050316, 'node_id': 'MDEyOk9yZ2FuaXphdGlvbjUwNTAzMTY=', 'avatar_url': 'https://avatars.githubusercontent.com/u/5050316?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/dolphin-emu', 'html_url': 'https://github.com/dolphin-emu', 'followers_url': 'https://api.github.com/users/dolphin-emu/followers', 'following_url': 'https://api.github.com/users/dolphin-emu/following{/other_user}', 'gists_url': 'https://api.github.com/users/dolphin-emu/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/dolphin-emu/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/dolphin-emu/subscriptions', 'organizations_url': 'https://api.github.com/users/dolphin-emu/orgs', 'repos_url': 'https://api.github.com/users/dolphin-emu/repos', 'events_url': 'https://api.github.com/users/dolphin-emu/events{/privacy}', 'received_events_url': 'https://api.github.com/users/dolphin-emu/received_events', 'type': 'Organization', 'user_view_type': 'public', 'site_admin': False}, 'html_url': 'https://github.com/dolphin-emu/dolphin', 'description': 'Dolphin is a GameCube / Wii emulator, allowing you to play games for these two platforms on PC with improvements.', 'fork': False, 'url': 'https://api.github.com/repos/dolphin-emu/dolphin', 'forks_url': 'https://api.github.com/repos/dolphin-emu/dolphin/forks', 'keys_url': 'https://api.github.com/repos/dolphin-emu/dolphin/keys{/key_id}', 'collaborators_url': 'https://api.github.com/repos/dolphin-emu/dolphin/collaborators{/collaborator}', 'teams_url': 'https://api.github.com/repos/dolphin-emu/dolphin/teams', 'hooks_url': 'https://api.github.com/repos/dolphin-emu/dolphin/hooks', 'issue_events_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/events{/number}', 'events_url': 'https://api.github.com/repos/dolphin-emu/dolphin/events', 'assignees_url': 'https://api.github.com/repos/dolphin-emu/dolphin/assignees{/user}', 'branches_url': 'https://api.github.com/repos/dolphin-emu/dolphin/branches{/branch}', 'tags_url': 'https://api.github.com/repos/dolphin-emu/dolphin/tags', 'blobs_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/blobs{/sha}', 'git_tags_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/tags{/sha}', 'git_refs_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/refs{/sha}', 'trees_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/trees{/sha}', 'statuses_url': 'https://api.github.com/repos/dolphin-emu/dolphin/statuses/{sha}', 'languages_url': 'https://api.github.com/repos/dolphin-emu/dolphin/languages', 'stargazers_url': 'https://api.github.com/repos/dolphin-emu/dolphin/stargazers', 'contributors_url': 'https://api.github.com/repos/dolphin-emu/dolphin/contributors', 'subscribers_url': 'https://api.github.com/repos/dolphin-emu/dolphin/subscribers', 'subscription_url': 'https://api.github.com/repos/dolphin-emu/dolphin/subscription', 'commits_url': 'https://api.github.com/repos/dolphin-emu/dolphin/commits{/sha}', 'git_commits_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/commits{/sha}', 'comments_url': 'https://api.github.com/repos/dolphin-emu/dolphin/comments{/number}', 'issue_comment_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/comments{/number}', 'contents_url': 'https://api.github.com/repos/dolphin-emu/dolphin/contents/{+path}', 'compare_url': 'https://api.github.com/repos/dolphin-emu/dolphin/compare/{base}...{head}', 'merges_url': 'https://api.github.com/repos/dolphin-emu/dolphin/merges', 'archive_url': 'https://api.github.com/repos/dolphin-emu/dolphin/{archive_format}{/ref}', 'downloads_url': 'https://api.github.com/repos/dolphin-emu/dolphin/downloads', 'issues_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues{/number}', 'pulls_url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls{/number}', 'milestones_url': 'https://api.github.com/repos/dolphin-emu/dolphin/milestones{/number}', 'notifications_url': 'https://api.github.com/repos/dolphin-emu/dolphin/notifications{?since,all,participating}', 'labels_url': 'https://api.github.com/repos/dolphin-emu/dolphin/labels{/name}', 'releases_url': 'https://api.github.com/repos/dolphin-emu/dolphin/releases{/id}', 'deployments_url': 'https://api.github.com/repos/dolphin-emu/dolphin/deployments', 'created_at': '2013-07-22T09:07:57Z', 'updated_at': '2026-07-18T18:44:16Z', 'pushed_at': '2026-07-18T10:34:54Z', 'git_url': 'git://github.com/dolphin-emu/dolphin.git', 'ssh_url': 'git@github.com:dolphin-emu/dolphin.git', 'clone_url': 'https://github.com/dolphin-emu/dolphin.git', 'svn_url': 'https://github.com/dolphin-emu/dolphin', 'homepage': 'https://dolphin-emu.org', 'size': 558448, 'stargazers_count': 15272, 'watchers_count': 15272, 'language': 'C++', 'has_issues': False, 'has_projects': False, 'has_downloads': True, 'has_wiki': True, 'has_pages': False, 'has_discussions': False, 'forks_count': 3162, 'mirror_url': None, 'archived': False, 'disabled': False, 'open_issues_count': 446, 'license': {'key': 'other', 'name': 'Other', 'spdx_id': 'NOASSERTION', 'url': None, 'node_id': 'MDc6TGljZW5zZTA='}, 'allow_forking': True, 'is_template': False, 'web_commit_signoff_required': False, 'has_pull_requests': True, 'pull_request_creation_policy': 'all', 'topics': ['cpp', 'emulation', 'emulator', 'gamecube', 'wii'], 'visibility': 'public', 'forks': 3162, 'open_issues': 446, 'watchers': 15272, 'default_branch': 'master', 'allow_squash_merge': False, 'allow_merge_commit': True, 'allow_rebase_merge': False, 'allow_auto_merge': False, 'delete_branch_on_merge': False, 'allow_update_branch': False, 'use_squash_pr_title_as_default': False, 'squash_merge_commit_message': 'COMMIT_MESSAGES', 'squash_merge_commit_title': 'COMMIT_OR_PR_TITLE', 'merge_commit_message': 'PR_TITLE', 'merge_commit_title': 'MERGE_MESSAGE'}}, '_links': {'self': {'href': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/14731'}, 'html': {'href': 'https://github.com/dolphin-emu/dolphin/pull/14731'}, 'issue': {'href': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/14731'}, 'comments': {'href': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/14731/comments'}, 'review_comments': {'href': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/14731/comments'}, 'review_comment': {'href': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/comments{/number}'}, 'commits': {'href': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/14731/commits'}, 'statuses': {'href': 'https://api.github.com/repos/dolphin-emu/dolphin/statuses/24b41d58df2315831b74f76b95417f2739d02f9d'}}, 'author_association': 'NONE', 'auto_merge': None, 'assignee': None, 'active_lock_reason': None}, 'repository': {'id': 11577304, 'node_id': 'MDEwOlJlcG9zaXRvcnkxMTU3NzMwNA==', 'name': 'dolphin', 'full_name': 'dolphin-emu/dolphin', 'private': False, 'owner': {'login': 'dolphin-emu', 'id': 5050316, 'node_id': 'MDEyOk9yZ2FuaXphdGlvbjUwNTAzMTY=', 'avatar_url': 'https://avatars.githubusercontent.com/u/5050316?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/dolphin-emu', 'html_url': 'https://github.com/dolphin-emu', 'followers_url': 'https://api.github.com/users/dolphin-emu/followers', 'following_url': 'https://api.github.com/users/dolphin-emu/following{/other_user}', 'gists_url': 'https://api.github.com/users/dolphin-emu/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/dolphin-emu/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/dolphin-emu/subscriptions', 'organizations_url': 'https://api.github.com/users/dolphin-emu/orgs', 'repos_url': 'https://api.github.com/users/dolphin-emu/repos', 'events_url': 'https://api.github.com/users/dolphin-emu/events{/privacy}', 'received_events_url': 'https://api.github.com/users/dolphin-emu/received_events', 'type': 'Organization', 'user_view_type': 'public', 'site_admin': False}, 'html_url': 'https://github.com/dolphin-emu/dolphin', 'description': 'Dolphin is a GameCube / Wii emulator, allowing you to play games for these two platforms on PC with improvements.', 'fork': False, 'url': 'https://api.github.com/repos/dolphin-emu/dolphin', 'forks_url': 'https://api.github.com/repos/dolphin-emu/dolphin/forks', 'keys_url': 'https://api.github.com/repos/dolphin-emu/dolphin/keys{/key_id}', 'collaborators_url': 'https://api.github.com/repos/dolphin-emu/dolphin/collaborators{/collaborator}', 'teams_url': 'https://api.github.com/repos/dolphin-emu/dolphin/teams', 'hooks_url': 'https://api.github.com/repos/dolphin-emu/dolphin/hooks', 'issue_events_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/events{/number}', 'events_url': 'https://api.github.com/repos/dolphin-emu/dolphin/events', 'assignees_url': 'https://api.github.com/repos/dolphin-emu/dolphin/assignees{/user}', 'branches_url': 'https://api.github.com/repos/dolphin-emu/dolphin/branches{/branch}', 'tags_url': 'https://api.github.com/repos/dolphin-emu/dolphin/tags', 'blobs_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/blobs{/sha}', 'git_tags_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/tags{/sha}', 'git_refs_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/refs{/sha}', 'trees_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/trees{/sha}', 'statuses_url': 'https://api.github.com/repos/dolphin-emu/dolphin/statuses/{sha}', 'languages_url': 'https://api.github.com/repos/dolphin-emu/dolphin/languages', 'stargazers_url': 'https://api.github.com/repos/dolphin-emu/dolphin/stargazers', 'contributors_url': 'https://api.github.com/repos/dolphin-emu/dolphin/contributors', 'subscribers_url': 'https://api.github.com/repos/dolphin-emu/dolphin/subscribers', 'subscription_url': 'https://api.github.com/repos/dolphin-emu/dolphin/subscription', 'commits_url': 'https://api.github.com/repos/dolphin-emu/dolphin/commits{/sha}', 'git_commits_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/commits{/sha}', 'comments_url': 'https://api.github.com/repos/dolphin-emu/dolphin/comments{/number}', 'issue_comment_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/comments{/number}', 'contents_url': 'https://api.github.com/repos/dolphin-emu/dolphin/contents/{+path}', 'compare_url': 'https://api.github.com/repos/dolphin-emu/dolphin/compare/{base}...{head}', 'merges_url': 'https://api.github.com/repos/dolphin-emu/dolphin/merges', 'archive_url': 'https://api.github.com/repos/dolphin-emu/dolphin/{archive_format}{/ref}', 'downloads_url': 'https://api.github.com/repos/dolphin-emu/dolphin/downloads', 'issues_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues{/number}', 'pulls_url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls{/number}', 'milestones_url': 'https://api.github.com/repos/dolphin-emu/dolphin/milestones{/number}', 'notifications_url': 'https://api.github.com/repos/dolphin-emu/dolphin/notifications{?since,all,participating}', 'labels_url': 'https://api.github.com/repos/dolphin-emu/dolphin/labels{/name}', 'releases_url': 'https://api.github.com/repos/dolphin-emu/dolphin/releases{/id}', 'deployments_url': 'https://api.github.com/repos/dolphin-emu/dolphin/deployments', 'created_at': '2013-07-22T09:07:57Z', 'updated_at': '2026-07-18T18:44:16Z', 'pushed_at': '2026-07-18T10:34:54Z', 'git_url': 'git://github.com/dolphin-emu/dolphin.git', 'ssh_url': 'git@github.com:dolphin-emu/dolphin.git', 'clone_url': 'https://github.com/dolphin-emu/dolphin.git', 'svn_url': 'https://github.com/dolphin-emu/dolphin', 'homepage': 'https://dolphin-emu.org', 'size': 558448, 'stargazers_count': 15272, 'watchers_count': 15272, 'language': 'C++', 'has_issues': False, 'has_projects': False, 'has_downloads': True, 'has_wiki': True, 'has_pages': False, 'has_discussions': False, 'forks_count': 3162, 'mirror_url': None, 'archived': False, 'disabled': False, 'open_issues_count': 446, 'license': {'key': 'other', 'name': 'Other', 'spdx_id': 'NOASSERTION', 'url': None, 'node_id': 'MDc6TGljZW5zZTA='}, 'allow_forking': True, 'is_template': False, 'web_commit_signoff_required': False, 'has_pull_requests': True, 'pull_request_creation_policy': 'all', 'topics': ['cpp', 'emulation', 'emulator', 'gamecube', 'wii'], 'visibility': 'public', 'forks': 3162, 'open_issues': 446, 'watchers': 15272, 'default_branch': 'master', 'custom_properties': {}}, 'organization': {'login': 'dolphin-emu', 'id': 5050316, 'node_id': 'MDEyOk9yZ2FuaXphdGlvbjUwNTAzMTY=', 'url': 'https://api.github.com/orgs/dolphin-emu', 'repos_url': 'https://api.github.com/orgs/dolphin-emu/repos', 'events_url': 'https://api.github.com/orgs/dolphin-emu/events', 'hooks_url': 'https://api.github.com/orgs/dolphin-emu/hooks', 'issues_url': 'https://api.github.com/orgs/dolphin-emu/issues', 'members_url': 'https://api.github.com/orgs/dolphin-emu/members{/member}', 'public_members_url': 'https://api.github.com/orgs/dolphin-emu/public_members{/member}', 'avatar_url': 'https://avatars.githubusercontent.com/u/5050316?v=4', 'description': ''}, 'sender': {'login': 'phire', 'id': 138484, 'node_id': 'MDQ6VXNlcjEzODQ4NA==', 'avatar_url': 'https://avatars.githubusercontent.com/u/138484?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/phire', 'html_url': 'https://github.com/phire', 'followers_url': 'https://api.github.com/users/phire/followers', 'following_url': 'https://api.github.com/users/phire/following{/other_user}', 'gists_url': 'https://api.github.com/users/phire/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/phire/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/phire/subscriptions', 'organizations_url': 'https://api.github.com/users/phire/orgs', 'repos_url': 'https://api.github.com/users/phire/repos', 'events_url': 'https://api.github.com/users/phire/events{/privacy}', 'received_events_url': 'https://api.github.com/users/phire/received_events', 'type': 'User', 'user_view_type': 'public', 'site_admin': False}, 'installation': {'id': 35437981, 'node_id': 'MDIzOkludGVncmF0aW9uSW5zdGFsbGF0aW9uMzU0Mzc5ODE='}}, 'type': 'raw_gh_hook'}
2026-07-18T23:03:38.971208	{'source': 'webserver', 'gh_type': 'pull_request_review_comment', 'raw': {'action': 'edited', 'changes': {'body': {'from': "> ReadWiiDecrypted still contains manual AES decryption for stored blocks because VolumeWii::EncryptGroup calls it directly without checking SupportsReadWiiDecrypted\n\nBut you are calling `EncryptGroup` for blocks that don't have data, right? I don't see why this would be reachable."}}, 'comment': {'url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/comments/3609277919', 'pull_request_review_id': 4729322283, 'id': 3609277919, 'node_id': 'PRRC_kwDOALCn2M7XITXf', 'diff_hunk': '@@ -119,22 +144,191 @@ bool WbfsFileReader::ReadHeader()\n   return m_header.disc_table[0] != 0;\n }\n \n+bool WbfsFileReader::ReadNKitHeader()\n+{\n+  const u64 gap_type_blocks = (DL_DVD_SIZE + m_wbfs_sector_size - 1) / m_wbfs_sector_size;\n+  m_nkit_info = NKit::ReadHeaderFromFile(m_files[0].file, NKit::HEADER_OFFSET, gap_type_blocks);\n+  if (!m_nkit_info.valid)\n+    return false;\n+\n+  m_has_nkit_header = true;\n+  return true;\n+}\n+\n+bool WbfsFileReader::IsBlockStored(u64 block_index) const\n+{\n+  return block_index < m_blocks_per_disc && m_wlba_table[block_index] != 0;\n+}\n+\n+bool WbfsFileReader::IsGapJunk(u64 block_index) const\n+{\n+  return NKit::IsGapJunk(m_nkit_info.gap_type, block_index);\n+}\n+\n+void WbfsFileReader::GenerateJunkData(u64 disc_offset, u64 size, u8* out) const\n+{\n+  LaggedFibonacciGenerator::FillJunkData(out, static_cast<size_t>(size), disc_offset, m_disc_id,\n+                                         m_disc_num);\n+}\n+\n+void WbfsFileReader::ReadPartitionInfo()\n+{\n+  std::unique_ptr<VolumeDisc> volume = CreateDisc(CopyReader());\n+  if (!volume)\n+    return;\n+\n+  for (const Partition& partition : volume->GetPartitions())\n+  {\n+    const auto& ticket = volume->GetTicket(partition);\n+    const std::array<u8, 16> title_key = ticket.GetTitleKey();\n+\n+    u8 data_info[8];\n+    if (!Read(partition.offset + 0x2B8, 8, data_info))\n+      continue;\n+\n+    PartitionEntry entry;\n+    entry.data_offset = partition.offset + (static_cast<u64>(Common::swap32(data_info)) << 2);\n+    entry.data_size = static_cast<u64>(Common::swap32(data_info + 4)) << 2;\n+    entry.key = title_key;\n+    m_partitions.push_back(entry);\n+  }\n+}\n+\n+const WbfsFileReader::PartitionEntry* WbfsFileReader::FindPartition(u64 disc_offset) const\n+{\n+  for (const auto& p : m_partitions)\n+  {\n+    if (disc_offset >= p.data_offset && disc_offset < p.data_offset + p.data_size)\n+      return &p;\n+  }\n+  return nullptr;\n+}\n+\n+const WbfsFileReader::PartitionEntry*\n+WbfsFileReader::FindPartitionByDataOffset(u64 partition_data_offset) const\n+{\n+  for (const auto& p : m_partitions)\n+  {\n+    if (p.data_offset == partition_data_offset)\n+      return &p;\n+  }\n+  return nullptr;\n+}\n+\n+bool WbfsFileReader::SupportsReadWiiDecrypted(u64 offset, u64 size, u64 partition_data_offset) const\n+{\n+  if (!m_has_nkit_header)\n+    return false;\n+\n+  const u64 block_in_partition = offset / VolumeWii::BLOCK_DATA_SIZE;\n+  const u64 disc_offset = partition_data_offset + block_in_partition * VolumeWii::BLOCK_TOTAL_SIZE;\n+  const u64 wbfs_block = disc_offset >> m_header.wbfs_sector_shift;\n+\n+  return wbfs_block < m_blocks_per_disc && !IsBlockStored(wbfs_block);\n+}\n+\n+bool WbfsFileReader::ReadWiiDecrypted(u64 offset, u64 size, u8* out_ptr, u64 partition_data_offset)\n+{\n+  const PartitionEntry* pe = FindPartitionByDataOffset(partition_data_offset);\n+  if (!pe)\n+    return false;\n+\n+  auto aes_ctx = Common::AES::CreateContextDecrypt(pe->key.data());\n+  std::vector<u8> encrypted(VolumeWii::BLOCK_TOTAL_SIZE);\n+  std::vector<u8> decrypted(VolumeWii::BLOCK_DATA_SIZE);\n+\n+  while (size > 0)\n+  {\n+    const u64 block_in_partition = offset / VolumeWii::BLOCK_DATA_SIZE;\n+    const u64 offset_in_block = offset % VolumeWii::BLOCK_DATA_SIZE;\n+    const u64 bytes_in_block = VolumeWii::BLOCK_DATA_SIZE - offset_in_block;\n+    const size_t read_size = static_cast<size_t>(std::min(bytes_in_block, size));\n+\n+    const u64 disc_offset =\n+        partition_data_offset + block_in_partition * VolumeWii::BLOCK_TOTAL_SIZE;\n+    const u64 wbfs_block = disc_offset >> m_header.wbfs_sector_shift;\n+\n+    if (IsBlockStored(wbfs_block))\n+    {\n+      u64 available;\n+      auto& file = SeekToCluster(disc_offset, &available);\n+      if (available < VolumeWii::BLOCK_TOTAL_SIZE ||\n+          !file.Read(encrypted.data(), VolumeWii::BLOCK_TOTAL_SIZE))\n+        return false;\n+      VolumeWii::DecryptBlockData(encrypted.data(), decrypted.data(), aes_ctx.get());\n+      std::memcpy(out_ptr, decrypted.data() + offset_in_block, read_size);\n+    }', 'path': 'Source/Core/DiscIO/WbfsBlob.cpp', 'commit_id': '24b41d58df2315831b74f76b95417f2739d02f9d', 'original_commit_id': '24b41d58df2315831b74f76b95417f2739d02f9d', 'user': {'login': 'phire', 'id': 138484, 'node_id': 'MDQ6VXNlcjEzODQ4NA==', 'avatar_url': 'https://avatars.githubusercontent.com/u/138484?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/phire', 'html_url': 'https://github.com/phire', 'followers_url': 'https://api.github.com/users/phire/followers', 'following_url': 'https://api.github.com/users/phire/following{/other_user}', 'gists_url': 'https://api.github.com/users/phire/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/phire/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/phire/subscriptions', 'organizations_url': 'https://api.github.com/users/phire/orgs', 'repos_url': 'https://api.github.com/users/phire/repos', 'events_url': 'https://api.github.com/users/phire/events{/privacy}', 'received_events_url': 'https://api.github.com/users/phire/received_events', 'type': 'User', 'user_view_type': 'public', 'site_admin': False}, 'body': "> ReadWiiDecrypted still contains manual AES decryption for stored blocks because VolumeWii::EncryptGroup calls it directly without checking SupportsReadWiiDecrypted\n\nBut you are *only* calling `EncryptGroup` for blocks that don't have data, right? I don't see why this would be reachable.", 'created_at': '2026-07-18T22:05:05Z', 'updated_at': '2026-07-18T23:03:37Z', 'html_url': 'https://github.com/dolphin-emu/dolphin/pull/14731#discussion_r3609277919', 'pull_request_url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/14731', '_links': {'self': {'href': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/comments/3609277919'}, 'html': {'href': 'https://github.com/dolphin-emu/dolphin/pull/14731#discussion_r3609277919'}, 'pull_request': {'href': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/14731'}}, 'reactions': {'url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/comments/3609277919/reactions', 'total_count': 0, '+1': 0, '-1': 0, 'laugh': 0, 'hooray': 0, 'confused': 0, 'heart': 0, 'rocket': 0, 'eyes': 0}, 'start_line': 251, 'original_start_line': 251, 'start_side': 'RIGHT', 'line': 260, 'original_line': 260, 'side': 'RIGHT', 'author_association': 'MEMBER', 'original_position': 204, 'position': 204, 'subject_type': 'line'}, 'pull_request': {'url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/14731', 'id': 4056977334, 'node_id': 'PR_kwDOALCn2M7x0I-2', 'html_url': 'https://github.com/dolphin-emu/dolphin/pull/14731', 'diff_url': 'https://github.com/dolphin-emu/dolphin/pull/14731.diff', 'patch_url': 'https://github.com/dolphin-emu/dolphin/pull/14731.patch', 'issue_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/14731', 'number': 14731, 'state': 'open', 'locked': False, 'title': 'Convert To WBFS Support', 'user': {'login': 'thethiny', 'id': 6018214, 'node_id': 'MDQ6VXNlcjYwMTgyMTQ=', 'avatar_url': 'https://avatars.githubusercontent.com/u/6018214?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/thethiny', 'html_url': 'https://github.com/thethiny', 'followers_url': 'https://api.github.com/users/thethiny/followers', 'following_url': 'https://api.github.com/users/thethiny/following{/other_user}', 'gists_url': 'https://api.github.com/users/thethiny/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/thethiny/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/thethiny/subscriptions', 'organizations_url': 'https://api.github.com/users/thethiny/orgs', 'repos_url': 'https://api.github.com/users/thethiny/repos', 'events_url': 'https://api.github.com/users/thethiny/events{/privacy}', 'received_events_url': 'https://api.github.com/users/thethiny/received_events', 'type': 'User', 'user_view_type': 'public', 'site_admin': False}, 'body': "This PR introduces Conversion **to** WBFS support. WBFS is the format that is used by USB Loaders on a real Wii device.\r\n\r\n## Design decisions & hardcoded values\r\nThe writer uses fixed sector sizes that match what [libwbfs (the reference implementation by kwiirk)](https://github.com/kwiirk/wbfs/blob/master/libwbfs/libwbfs.c#L128-L134) computes for a standard single-layer Wii disc. These 2 hardcodes are stable and work correctly across all my testings.\r\n- HD sector shift: 9 (512 bytes)\r\n- WBFS sector shift: 21 (2 MiB)\r\nThese are not configurable via the UI. All existing WBFS tools use these values, and since the aim is to support USB Loaders then this has been tested and it is working on a real Wii.\r\n\r\nConverting from WBFS is not enabled. The existing `WbfsFileReader` reports `DataSizeType::UpperBound`, and `ShouldAllowConversion()` requires `Accurate`. I am able to support this but since it was hardcoded by the Dolphin team I thought a discussion is warranted.\r\n\r\n## Testing\r\n- Verified with DolphinTool header and DolphinTool verify\r\n- Verified with wit FILETYPE and wit DUMP (Wiimm's ISO Tools recognizes valid WBFS structure, partitions, encryption)\r\n- Tested ISO to WBFS and RVZ to WBFS conversions\r\n- Output file sizes match Wii Backup Manager when scrubbing is enabled (~0.1% difference), works when scrubbing is disabled.\r\n- Output WBFS files play correctly in Dolphin\r\n- Output WBFS files play correctly on a real Wii using USB Loader GX e25c4f3\r\n", 'created_at': '2026-07-15T01:16:25Z', 'updated_at': '2026-07-18T22:26:23Z', 'closed_at': None, 'merged_at': None, 'merge_commit_sha': '228f93416dd80eb09da834ad7852c8eaa4d9212b', 'assignees': [], 'requested_reviewers': [], 'requested_teams': [], 'labels': [], 'milestone': None, 'draft': False, 'commits_url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/14731/commits', 'review_comments_url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/14731/comments', 'review_comment_url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/comments{/number}', 'comments_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/14731/comments', 'statuses_url': 'https://api.github.com/repos/dolphin-emu/dolphin/statuses/24b41d58df2315831b74f76b95417f2739d02f9d', 'head': {'label': 'thethiny:wbfs-conversion', 'ref': 'wbfs-conversion', 'sha': '24b41d58df2315831b74f76b95417f2739d02f9d', 'user': {'login': 'thethiny', 'id': 6018214, 'node_id': 'MDQ6VXNlcjYwMTgyMTQ=', 'avatar_url': 'https://avatars.githubusercontent.com/u/6018214?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/thethiny', 'html_url': 'https://github.com/thethiny', 'followers_url': 'https://api.github.com/users/thethiny/followers', 'following_url': 'https://api.github.com/users/thethiny/following{/other_user}', 'gists_url': 'https://api.github.com/users/thethiny/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/thethiny/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/thethiny/subscriptions', 'organizations_url': 'https://api.github.com/users/thethiny/orgs', 'repos_url': 'https://api.github.com/users/thethiny/repos', 'events_url': 'https://api.github.com/users/thethiny/events{/privacy}', 'received_events_url': 'https://api.github.com/users/thethiny/received_events', 'type': 'User', 'user_view_type': 'public', 'site_admin': False}, 'repo': {'id': 1298654395, 'node_id': 'R_kgDOTWfkuw', 'name': 'dolphin', 'full_name': 'thethiny/dolphin', 'private': False, 'owner': {'login': 'thethiny', 'id': 6018214, 'node_id': 'MDQ6VXNlcjYwMTgyMTQ=', 'avatar_url': 'https://avatars.githubusercontent.com/u/6018214?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/thethiny', 'html_url': 'https://github.com/thethiny', 'followers_url': 'https://api.github.com/users/thethiny/followers', 'following_url': 'https://api.github.com/users/thethiny/following{/other_user}', 'gists_url': 'https://api.github.com/users/thethiny/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/thethiny/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/thethiny/subscriptions', 'organizations_url': 'https://api.github.com/users/thethiny/orgs', 'repos_url': 'https://api.github.com/users/thethiny/repos', 'events_url': 'https://api.github.com/users/thethiny/events{/privacy}', 'received_events_url': 'https://api.github.com/users/thethiny/received_events', 'type': 'User', 'user_view_type': 'public', 'site_admin': False}, 'html_url': 'https://github.com/thethiny/dolphin', 'description': 'Dolphin is a GameCube / Wii emulator, allowing you to play games for these two platforms on PC with improvements.', 'fork': True, 'url': 'https://api.github.com/repos/thethiny/dolphin', 'forks_url': 'https://api.github.com/repos/thethiny/dolphin/forks', 'keys_url': 'https://api.github.com/repos/thethiny/dolphin/keys{/key_id}', 'collaborators_url': 'https://api.github.com/repos/thethiny/dolphin/collaborators{/collaborator}', 'teams_url': 'https://api.github.com/repos/thethiny/dolphin/teams', 'hooks_url': 'https://api.github.com/repos/thethiny/dolphin/hooks', 'issue_events_url': 'https://api.github.com/repos/thethiny/dolphin/issues/events{/number}', 'events_url': 'https://api.github.com/repos/thethiny/dolphin/events', 'assignees_url': 'https://api.github.com/repos/thethiny/dolphin/assignees{/user}', 'branches_url': 'https://api.github.com/repos/thethiny/dolphin/branches{/branch}', 'tags_url': 'https://api.github.com/repos/thethiny/dolphin/tags', 'blobs_url': 'https://api.github.com/repos/thethiny/dolphin/git/blobs{/sha}', 'git_tags_url': 'https://api.github.com/repos/thethiny/dolphin/git/tags{/sha}', 'git_refs_url': 'https://api.github.com/repos/thethiny/dolphin/git/refs{/sha}', 'trees_url': 'https://api.github.com/repos/thethiny/dolphin/git/trees{/sha}', 'statuses_url': 'https://api.github.com/repos/thethiny/dolphin/statuses/{sha}', 'languages_url': 'https://api.github.com/repos/thethiny/dolphin/languages', 'stargazers_url': 'https://api.github.com/repos/thethiny/dolphin/stargazers', 'contributors_url': 'https://api.github.com/repos/thethiny/dolphin/contributors', 'subscribers_url': 'https://api.github.com/repos/thethiny/dolphin/subscribers', 'subscription_url': 'https://api.github.com/repos/thethiny/dolphin/subscription', 'commits_url': 'https://api.github.com/repos/thethiny/dolphin/commits{/sha}', 'git_commits_url': 'https://api.github.com/repos/thethiny/dolphin/git/commits{/sha}', 'comments_url': 'https://api.github.com/repos/thethiny/dolphin/comments{/number}', 'issue_comment_url': 'https://api.github.com/repos/thethiny/dolphin/issues/comments{/number}', 'contents_url': 'https://api.github.com/repos/thethiny/dolphin/contents/{+path}', 'compare_url': 'https://api.github.com/repos/thethiny/dolphin/compare/{base}...{head}', 'merges_url': 'https://api.github.com/repos/thethiny/dolphin/merges', 'archive_url': 'https://api.github.com/repos/thethiny/dolphin/{archive_format}{/ref}', 'downloads_url': 'https://api.github.com/repos/thethiny/dolphin/downloads', 'issues_url': 'https://api.github.com/repos/thethiny/dolphin/issues{/number}', 'pulls_url': 'https://api.github.com/repos/thethiny/dolphin/pulls{/number}', 'milestones_url': 'https://api.github.com/repos/thethiny/dolphin/milestones{/number}', 'notifications_url': 'https://api.github.com/repos/thethiny/dolphin/notifications{?since,all,participating}', 'labels_url': 'https://api.github.com/repos/thethiny/dolphin/labels{/name}', 'releases_url': 'https://api.github.com/repos/thethiny/dolphin/releases{/id}', 'deployments_url': 'https://api.github.com/repos/thethiny/dolphin/deployments', 'created_at': '2026-07-12T22:09:13Z', 'updated_at': '2026-07-12T22:09:13Z', 'pushed_at': '2026-07-18T20:35:03Z', 'git_url': 'git://github.com/thethiny/dolphin.git', 'ssh_url': 'git@github.com:thethiny/dolphin.git', 'clone_url': 'https://github.com/thethiny/dolphin.git', 'svn_url': 'https://github.com/thethiny/dolphin', 'homepage': 'https://dolphin-emu.org', 'size': 515471, 'stargazers_count': 0, 'watchers_count': 0, 'language': None, 'has_issues': False, 'has_projects': True, 'has_downloads': True, 'has_wiki': True, 'has_pages': False, 'has_discussions': False, 'forks_count': 0, 'mirror_url': None, 'archived': False, 'disabled': False, 'open_issues_count': 0, 'license': {'key': 'other', 'name': 'Other', 'spdx_id': 'NOASSERTION', 'url': None, 'node_id': 'MDc6TGljZW5zZTA='}, 'allow_forking': True, 'is_template': False, 'web_commit_signoff_required': False, 'has_pull_requests': True, 'pull_request_creation_policy': 'all', 'topics': [], 'visibility': 'public', 'forks': 0, 'open_issues': 0, 'watchers': 0, 'default_branch': 'master', 'allow_squash_merge': True, 'allow_merge_commit': True, 'allow_rebase_merge': True, 'allow_auto_merge': False, 'delete_branch_on_merge': False, 'allow_update_branch': False, 'use_squash_pr_title_as_default': False, 'squash_merge_commit_message': 'COMMIT_MESSAGES', 'squash_merge_commit_title': 'COMMIT_OR_PR_TITLE', 'merge_commit_message': 'PR_TITLE', 'merge_commit_title': 'MERGE_MESSAGE'}}, 'base': {'label': 'dolphin-emu:master', 'ref': 'master', 'sha': 'd3b2943807dd0073f7767947466dd73cccfef319', 'user': {'login': 'dolphin-emu', 'id': 5050316, 'node_id': 'MDEyOk9yZ2FuaXphdGlvbjUwNTAzMTY=', 'avatar_url': 'https://avatars.githubusercontent.com/u/5050316?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/dolphin-emu', 'html_url': 'https://github.com/dolphin-emu', 'followers_url': 'https://api.github.com/users/dolphin-emu/followers', 'following_url': 'https://api.github.com/users/dolphin-emu/following{/other_user}', 'gists_url': 'https://api.github.com/users/dolphin-emu/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/dolphin-emu/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/dolphin-emu/subscriptions', 'organizations_url': 'https://api.github.com/users/dolphin-emu/orgs', 'repos_url': 'https://api.github.com/users/dolphin-emu/repos', 'events_url': 'https://api.github.com/users/dolphin-emu/events{/privacy}', 'received_events_url': 'https://api.github.com/users/dolphin-emu/received_events', 'type': 'Organization', 'user_view_type': 'public', 'site_admin': False}, 'repo': {'id': 11577304, 'node_id': 'MDEwOlJlcG9zaXRvcnkxMTU3NzMwNA==', 'name': 'dolphin', 'full_name': 'dolphin-emu/dolphin', 'private': False, 'owner': {'login': 'dolphin-emu', 'id': 5050316, 'node_id': 'MDEyOk9yZ2FuaXphdGlvbjUwNTAzMTY=', 'avatar_url': 'https://avatars.githubusercontent.com/u/5050316?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/dolphin-emu', 'html_url': 'https://github.com/dolphin-emu', 'followers_url': 'https://api.github.com/users/dolphin-emu/followers', 'following_url': 'https://api.github.com/users/dolphin-emu/following{/other_user}', 'gists_url': 'https://api.github.com/users/dolphin-emu/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/dolphin-emu/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/dolphin-emu/subscriptions', 'organizations_url': 'https://api.github.com/users/dolphin-emu/orgs', 'repos_url': 'https://api.github.com/users/dolphin-emu/repos', 'events_url': 'https://api.github.com/users/dolphin-emu/events{/privacy}', 'received_events_url': 'https://api.github.com/users/dolphin-emu/received_events', 'type': 'Organization', 'user_view_type': 'public', 'site_admin': False}, 'html_url': 'https://github.com/dolphin-emu/dolphin', 'description': 'Dolphin is a GameCube / Wii emulator, allowing you to play games for these two platforms on PC with improvements.', 'fork': False, 'url': 'https://api.github.com/repos/dolphin-emu/dolphin', 'forks_url': 'https://api.github.com/repos/dolphin-emu/dolphin/forks', 'keys_url': 'https://api.github.com/repos/dolphin-emu/dolphin/keys{/key_id}', 'collaborators_url': 'https://api.github.com/repos/dolphin-emu/dolphin/collaborators{/collaborator}', 'teams_url': 'https://api.github.com/repos/dolphin-emu/dolphin/teams', 'hooks_url': 'https://api.github.com/repos/dolphin-emu/dolphin/hooks', 'issue_events_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/events{/number}', 'events_url': 'https://api.github.com/repos/dolphin-emu/dolphin/events', 'assignees_url': 'https://api.github.com/repos/dolphin-emu/dolphin/assignees{/user}', 'branches_url': 'https://api.github.com/repos/dolphin-emu/dolphin/branches{/branch}', 'tags_url': 'https://api.github.com/repos/dolphin-emu/dolphin/tags', 'blobs_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/blobs{/sha}', 'git_tags_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/tags{/sha}', 'git_refs_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/refs{/sha}', 'trees_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/trees{/sha}', 'statuses_url': 'https://api.github.com/repos/dolphin-emu/dolphin/statuses/{sha}', 'languages_url': 'https://api.github.com/repos/dolphin-emu/dolphin/languages', 'stargazers_url': 'https://api.github.com/repos/dolphin-emu/dolphin/stargazers', 'contributors_url': 'https://api.github.com/repos/dolphin-emu/dolphin/contributors', 'subscribers_url': 'https://api.github.com/repos/dolphin-emu/dolphin/subscribers', 'subscription_url': 'https://api.github.com/repos/dolphin-emu/dolphin/subscription', 'commits_url': 'https://api.github.com/repos/dolphin-emu/dolphin/commits{/sha}', 'git_commits_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/commits{/sha}', 'comments_url': 'https://api.github.com/repos/dolphin-emu/dolphin/comments{/number}', 'issue_comment_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/comments{/number}', 'contents_url': 'https://api.github.com/repos/dolphin-emu/dolphin/contents/{+path}', 'compare_url': 'https://api.github.com/repos/dolphin-emu/dolphin/compare/{base}...{head}', 'merges_url': 'https://api.github.com/repos/dolphin-emu/dolphin/merges', 'archive_url': 'https://api.github.com/repos/dolphin-emu/dolphin/{archive_format}{/ref}', 'downloads_url': 'https://api.github.com/repos/dolphin-emu/dolphin/downloads', 'issues_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues{/number}', 'pulls_url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls{/number}', 'milestones_url': 'https://api.github.com/repos/dolphin-emu/dolphin/milestones{/number}', 'notifications_url': 'https://api.github.com/repos/dolphin-emu/dolphin/notifications{?since,all,participating}', 'labels_url': 'https://api.github.com/repos/dolphin-emu/dolphin/labels{/name}', 'releases_url': 'https://api.github.com/repos/dolphin-emu/dolphin/releases{/id}', 'deployments_url': 'https://api.github.com/repos/dolphin-emu/dolphin/deployments', 'created_at': '2013-07-22T09:07:57Z', 'updated_at': '2026-07-18T18:44:16Z', 'pushed_at': '2026-07-18T10:34:54Z', 'git_url': 'git://github.com/dolphin-emu/dolphin.git', 'ssh_url': 'git@github.com:dolphin-emu/dolphin.git', 'clone_url': 'https://github.com/dolphin-emu/dolphin.git', 'svn_url': 'https://github.com/dolphin-emu/dolphin', 'homepage': 'https://dolphin-emu.org', 'size': 558448, 'stargazers_count': 15272, 'watchers_count': 15272, 'language': 'C++', 'has_issues': False, 'has_projects': False, 'has_downloads': True, 'has_wiki': True, 'has_pages': False, 'has_discussions': False, 'forks_count': 3162, 'mirror_url': None, 'archived': False, 'disabled': False, 'open_issues_count': 446, 'license': {'key': 'other', 'name': 'Other', 'spdx_id': 'NOASSERTION', 'url': None, 'node_id': 'MDc6TGljZW5zZTA='}, 'allow_forking': True, 'is_template': False, 'web_commit_signoff_required': False, 'has_pull_requests': True, 'pull_request_creation_policy': 'all', 'topics': ['cpp', 'emulation', 'emulator', 'gamecube', 'wii'], 'visibility': 'public', 'forks': 3162, 'open_issues': 446, 'watchers': 15272, 'default_branch': 'master', 'allow_squash_merge': False, 'allow_merge_commit': True, 'allow_rebase_merge': False, 'allow_auto_merge': False, 'delete_branch_on_merge': False, 'allow_update_branch': False, 'use_squash_pr_title_as_default': False, 'squash_merge_commit_message': 'COMMIT_MESSAGES', 'squash_merge_commit_title': 'COMMIT_OR_PR_TITLE', 'merge_commit_message': 'PR_TITLE', 'merge_commit_title': 'MERGE_MESSAGE'}}, '_links': {'self': {'href': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/14731'}, 'html': {'href': 'https://github.com/dolphin-emu/dolphin/pull/14731'}, 'issue': {'href': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/14731'}, 'comments': {'href': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/14731/comments'}, 'review_comments': {'href': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/14731/comments'}, 'review_comment': {'href': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/comments{/number}'}, 'commits': {'href': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/14731/commits'}, 'statuses': {'href': 'https://api.github.com/repos/dolphin-emu/dolphin/statuses/24b41d58df2315831b74f76b95417f2739d02f9d'}}, 'author_association': 'NONE', 'auto_merge': None, 'assignee': None, 'active_lock_reason': None}, 'repository': {'id': 11577304, 'node_id': 'MDEwOlJlcG9zaXRvcnkxMTU3NzMwNA==', 'name': 'dolphin', 'full_name': 'dolphin-emu/dolphin', 'private': False, 'owner': {'login': 'dolphin-emu', 'id': 5050316, 'node_id': 'MDEyOk9yZ2FuaXphdGlvbjUwNTAzMTY=', 'avatar_url': 'https://avatars.githubusercontent.com/u/5050316?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/dolphin-emu', 'html_url': 'https://github.com/dolphin-emu', 'followers_url': 'https://api.github.com/users/dolphin-emu/followers', 'following_url': 'https://api.github.com/users/dolphin-emu/following{/other_user}', 'gists_url': 'https://api.github.com/users/dolphin-emu/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/dolphin-emu/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/dolphin-emu/subscriptions', 'organizations_url': 'https://api.github.com/users/dolphin-emu/orgs', 'repos_url': 'https://api.github.com/users/dolphin-emu/repos', 'events_url': 'https://api.github.com/users/dolphin-emu/events{/privacy}', 'received_events_url': 'https://api.github.com/users/dolphin-emu/received_events', 'type': 'Organization', 'user_view_type': 'public', 'site_admin': False}, 'html_url': 'https://github.com/dolphin-emu/dolphin', 'description': 'Dolphin is a GameCube / Wii emulator, allowing you to play games for these two platforms on PC with improvements.', 'fork': False, 'url': 'https://api.github.com/repos/dolphin-emu/dolphin', 'forks_url': 'https://api.github.com/repos/dolphin-emu/dolphin/forks', 'keys_url': 'https://api.github.com/repos/dolphin-emu/dolphin/keys{/key_id}', 'collaborators_url': 'https://api.github.com/repos/dolphin-emu/dolphin/collaborators{/collaborator}', 'teams_url': 'https://api.github.com/repos/dolphin-emu/dolphin/teams', 'hooks_url': 'https://api.github.com/repos/dolphin-emu/dolphin/hooks', 'issue_events_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/events{/number}', 'events_url': 'https://api.github.com/repos/dolphin-emu/dolphin/events', 'assignees_url': 'https://api.github.com/repos/dolphin-emu/dolphin/assignees{/user}', 'branches_url': 'https://api.github.com/repos/dolphin-emu/dolphin/branches{/branch}', 'tags_url': 'https://api.github.com/repos/dolphin-emu/dolphin/tags', 'blobs_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/blobs{/sha}', 'git_tags_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/tags{/sha}', 'git_refs_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/refs{/sha}', 'trees_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/trees{/sha}', 'statuses_url': 'https://api.github.com/repos/dolphin-emu/dolphin/statuses/{sha}', 'languages_url': 'https://api.github.com/repos/dolphin-emu/dolphin/languages', 'stargazers_url': 'https://api.github.com/repos/dolphin-emu/dolphin/stargazers', 'contributors_url': 'https://api.github.com/repos/dolphin-emu/dolphin/contributors', 'subscribers_url': 'https://api.github.com/repos/dolphin-emu/dolphin/subscribers', 'subscription_url': 'https://api.github.com/repos/dolphin-emu/dolphin/subscription', 'commits_url': 'https://api.github.com/repos/dolphin-emu/dolphin/commits{/sha}', 'git_commits_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/commits{/sha}', 'comments_url': 'https://api.github.com/repos/dolphin-emu/dolphin/comments{/number}', 'issue_comment_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/comments{/number}', 'contents_url': 'https://api.github.com/repos/dolphin-emu/dolphin/contents/{+path}', 'compare_url': 'https://api.github.com/repos/dolphin-emu/dolphin/compare/{base}...{head}', 'merges_url': 'https://api.github.com/repos/dolphin-emu/dolphin/merges', 'archive_url': 'https://api.github.com/repos/dolphin-emu/dolphin/{archive_format}{/ref}', 'downloads_url': 'https://api.github.com/repos/dolphin-emu/dolphin/downloads', 'issues_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues{/number}', 'pulls_url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls{/number}', 'milestones_url': 'https://api.github.com/repos/dolphin-emu/dolphin/milestones{/number}', 'notifications_url': 'https://api.github.com/repos/dolphin-emu/dolphin/notifications{?since,all,participating}', 'labels_url': 'https://api.github.com/repos/dolphin-emu/dolphin/labels{/name}', 'releases_url': 'https://api.github.com/repos/dolphin-emu/dolphin/releases{/id}', 'deployments_url': 'https://api.github.com/repos/dolphin-emu/dolphin/deployments', 'created_at': '2013-07-22T09:07:57Z', 'updated_at': '2026-07-18T18:44:16Z', 'pushed_at': '2026-07-18T10:34:54Z', 'git_url': 'git://github.com/dolphin-emu/dolphin.git', 'ssh_url': 'git@github.com:dolphin-emu/dolphin.git', 'clone_url': 'https://github.com/dolphin-emu/dolphin.git', 'svn_url': 'https://github.com/dolphin-emu/dolphin', 'homepage': 'https://dolphin-emu.org', 'size': 558448, 'stargazers_count': 15272, 'watchers_count': 15272, 'language': 'C++', 'has_issues': False, 'has_projects': False, 'has_downloads': True, 'has_wiki': True, 'has_pages': False, 'has_discussions': False, 'forks_count': 3162, 'mirror_url': None, 'archived': False, 'disabled': False, 'open_issues_count': 446, 'license': {'key': 'other', 'name': 'Other', 'spdx_id': 'NOASSERTION', 'url': None, 'node_id': 'MDc6TGljZW5zZTA='}, 'allow_forking': True, 'is_template': False, 'web_commit_signoff_required': False, 'has_pull_requests': True, 'pull_request_creation_policy': 'all', 'topics': ['cpp', 'emulation', 'emulator', 'gamecube', 'wii'], 'visibility': 'public', 'forks': 3162, 'open_issues': 446, 'watchers': 15272, 'default_branch': 'master', 'custom_properties': {}}, 'organization': {'login': 'dolphin-emu', 'id': 5050316, 'node_id': 'MDEyOk9yZ2FuaXphdGlvbjUwNTAzMTY=', 'url': 'https://api.github.com/orgs/dolphin-emu', 'repos_url': 'https://api.github.com/orgs/dolphin-emu/repos', 'events_url': 'https://api.github.com/orgs/dolphin-emu/events', 'hooks_url': 'https://api.github.com/orgs/dolphin-emu/hooks', 'issues_url': 'https://api.github.com/orgs/dolphin-emu/issues', 'members_url': 'https://api.github.com/orgs/dolphin-emu/members{/member}', 'public_members_url': 'https://api.github.com/orgs/dolphin-emu/public_members{/member}', 'avatar_url': 'https://avatars.githubusercontent.com/u/5050316?v=4', 'description': ''}, 'sender': {'login': 'phire', 'id': 138484, 'node_id': 'MDQ6VXNlcjEzODQ4NA==', 'avatar_url': 'https://avatars.githubusercontent.com/u/138484?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/phire', 'html_url': 'https://github.com/phire', 'followers_url': 'https://api.github.com/users/phire/followers', 'following_url': 'https://api.github.com/users/phire/following{/other_user}', 'gists_url': 'https://api.github.com/users/phire/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/phire/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/phire/subscriptions', 'organizations_url': 'https://api.github.com/users/phire/orgs', 'repos_url': 'https://api.github.com/users/phire/repos', 'events_url': 'https://api.github.com/users/phire/events{/privacy}', 'received_events_url': 'https://api.github.com/users/phire/received_events', 'type': 'User', 'user_view_type': 'public', 'site_admin': False}, 'installation': {'id': 35437981, 'node_id': 'MDIzOkludGVncmF0aW9uSW5zdGFsbGF0aW9uMzU0Mzc5ODE='}}, 'type': 'raw_gh_hook'}
2026-07-18T22:54:54.428660	{'source': 'webserver', 'gh_type': 'pull_request_review', 'raw': {'action': 'submitted', 'review': {'id': 4729435306, 'node_id': 'PRR_kwDOALCn2M8AAAABGeV0qg', 'user': {'login': 'phire', 'id': 138484, 'node_id': 'MDQ6VXNlcjEzODQ4NA==', 'avatar_url': 'https://avatars.githubusercontent.com/u/138484?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/phire', 'html_url': 'https://github.com/phire', 'followers_url': 'https://api.github.com/users/phire/followers', 'following_url': 'https://api.github.com/users/phire/following{/other_user}', 'gists_url': 'https://api.github.com/users/phire/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/phire/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/phire/subscriptions', 'organizations_url': 'https://api.github.com/users/phire/orgs', 'repos_url': 'https://api.github.com/users/phire/repos', 'events_url': 'https://api.github.com/users/phire/events{/privacy}', 'received_events_url': 'https://api.github.com/users/phire/received_events', 'type': 'User', 'user_view_type': 'public', 'site_admin': False}, 'body': None, 'commit_id': '10a2596bc28392601c55b688715e4a65148af2c8', 'state': 'approved', 'html_url': 'https://github.com/dolphin-emu/dolphin/pull/14475#pullrequestreview-4729435306', 'pull_request_url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/14475', '_links': {'html': {'href': 'https://github.com/dolphin-emu/dolphin/pull/14475#pullrequestreview-4729435306'}, 'pull_request': {'href': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/14475'}}, 'submitted_at': '2026-07-18T22:54:52Z', 'updated_at': '2026-07-18T22:54:52Z', 'author_association': 'MEMBER'}, 'pull_request': {'url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/14475', 'id': 3404082578, 'node_id': 'PR_kwDOALCn2M7K5i2S', 'html_url': 'https://github.com/dolphin-emu/dolphin/pull/14475', 'diff_url': 'https://github.com/dolphin-emu/dolphin/pull/14475.diff', 'patch_url': 'https://github.com/dolphin-emu/dolphin/pull/14475.patch', 'issue_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/14475', 'number': 14475, 'state': 'open', 'locked': False, 'title': 'CMake: Replace the Visual Studio project', 'user': {'login': 'JoshuaVandaele', 'id': 24195176, 'node_id': 'MDQ6VXNlcjI0MTk1MTc2', 'avatar_url': 'https://avatars.githubusercontent.com/u/24195176?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/JoshuaVandaele', 'html_url': 'https://github.com/JoshuaVandaele', 'followers_url': 'https://api.github.com/users/JoshuaVandaele/followers', 'following_url': 'https://api.github.com/users/JoshuaVandaele/following{/other_user}', 'gists_url': 'https://api.github.com/users/JoshuaVandaele/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/JoshuaVandaele/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/JoshuaVandaele/subscriptions', 'organizations_url': 'https://api.github.com/users/JoshuaVandaele/orgs', 'repos_url': 'https://api.github.com/users/JoshuaVandaele/repos', 'events_url': 'https://api.github.com/users/JoshuaVandaele/events{/privacy}', 'received_events_url': 'https://api.github.com/users/JoshuaVandaele/received_events', 'type': 'User', 'user_view_type': 'public', 'site_admin': False}, 'body': 'The Visual Studio project is currently used to compile Dolphin on Windows, while CMake is used for all other platforms.\r\n\r\nThis difference has become a maintenance burden when introducing new dependencies, as it effectively doubles the amount of work and requires the developer to be familiar with both CMake and Visual Studio projects. Additionally, most dependencies do not provide Visual Studio projects, which means they need to be created and maintained by us, something that is very time-consuming and error-prone.\r\n\r\nThe situation has become cumbersome enough that the Visual Studio project now invokes CMake to configure and build larger dependencies, such as glslang.\r\n\r\n## Changes\r\n\r\n### Unification of the Output, Sys, and Translation Directories\r\n\r\nPreviously, on Windows the output directory was located in the `/Binary/<architecture>/` directory, whereas the output directory is located under `build/Binaries` for other platforms. Both platforms now output to `/build/<release|debug>/<architecture>/Binaries`.\r\n\r\nOn Non-Windows and non-Apple platforms, the Sys directory had a set location unless the `LINUX_LOCAL_DEV` flag was set, in which case Dolphin used a location relative to the executable. This is no longer the case, Dolphin will now first check for the existence of a Sys folder next to the Dolphin executable, before falling back to the defined SYSDATA directory. During build time, the Sys directory is now unconditionally Symlinked next to the executable, similar to the behavior on Windows, which copied the required files.\r\nWith this change, the `LINUX_LOCAL_DEV` flag is no longer required, and therefore has been removed.\r\n\r\n> [!WARNING]\r\n> Because creating symbolic links on Windows normally require a special permission, we fall back to copying with a warning unless [Developer Mode](https://learn.microsoft.com/windows/advanced-settings/developer-mode) is enabled.\r\n\r\nThe translation directories have also been merged on both platforms, in a similar fashion to the Sys directory.\r\n\r\n### Introducing CMakePresets, Replacing the Old CMakeSettings\r\n\r\nIt adds presets for **Debug** and **Release** profiles for both **x64** and **ARM64** architectures, as well as **Generic builds**.\r\nPresets can be used using [Visual Studio\'s built-in CMakePresets support](https://learn.microsoft.com/en-us/cpp/build/cmake-presets-vs?view=msvc-170), or [Visual Studio Code\'s CMake Tools](https://marketplace.visualstudio.com/items?itemName=ms-vscode.cmake-tools) extension.\r\n\r\nThey can also be used from the command line, like so:\r\n\r\n- x64/Unix-like/Ninja:\r\n  - Configure: `cmake --preset ninja-release-x64`\r\n  - Build: `cmake --build --preset ninja-build-release-x64`\r\n  - Configure + Build: `cmake --workflow --preset ninja-release-x64`\r\n- ARM64/Windows/Visual Studio:\r\n  - Configure: `cmake --preset visualstudio-release-arm64`\r\n  - Build: `cmake --build --preset visualstudio-build-release-arm64`\r\n  - Configure + Build: `cmake --workflow --preset visualstudio-release-arm64`\r\n\r\nThe Ninja generator is available to both Windows and Unix-likes, while the Visual Studio Generator is only available on Windows.\r\n\r\n#### Cross-Compiling\r\n\r\nOn **Windows**, the Visual Studio generator automatically takes care of everything, you just need to select an ARM64 preset.\r\n\r\nOn **Unix-likes**, to cross-compile you need to install a cross-compiler and (optionally) a sysroot of the target system.\r\nHere is an example to compile from x64 to ARM64 with a sysroot:\r\n\r\n- `cmake --preset ninja-release-arm64 -DCMAKE_C_COMPILER=aarch64-linux-gnu-gcc -DCMAKE_CXX_COMPILER=aarch64-linux-gnu-g++ -DCMAKE_SYSROOT=/opt/sysroots/aarch64-linux-gnu`\r\n- `cmake --build --preset ninja-build-release-arm64`\r\n\r\nYou will need a sysroot to link against Qt, since we do not vendor it in on platforms other than Windows.\r\n\r\n#### User Presets\r\n\r\nA `CMakeUserPresets.json` file may be created locally at the root of the project to further customize your presets.\r\n\r\n<details>\r\n\r\n<summary>Example: User Presets used to test this PR on Arch Linux with a generic Arch Linux ARM sysroot</summary>\r\n\r\n```json\r\n{\r\n  "version": 10,\r\n  "configurePresets": [\r\n    {\r\n      "name": "gcc-debug-arm64",\r\n      "inherits": "ninja-debug-arm64",\r\n      "cacheVariables": {\r\n        "CMAKE_C_COMPILER": "aarch64-linux-gnu-gcc",\r\n        "CMAKE_CXX_COMPILER": "aarch64-linux-gnu-g++",\r\n        "CMAKE_EXE_LINKER_FLAGS": "-L/opt/sysroots/ArchLinuxARM/lib",\r\n        "CMAKE_SYSROOT": "/opt/sysroots/ArchLinuxARM"\r\n      }\r\n    },\r\n    {\r\n      "name": "clang-debug-arm64",\r\n      "inherits": "ninja-debug-arm64",\r\n      "cacheVariables": {\r\n        "CMAKE_C_COMPILER": "clang",\r\n        "CMAKE_CXX_COMPILER": "clang++",\r\n        "CMAKE_C_FLAGS": "-target aarch64-linux-gnu",\r\n        "CMAKE_CXX_FLAGS": "-target aarch64-linux-gnu",\r\n        "CMAKE_SYSROOT": "/opt/sysroots/ArchLinuxARM"\r\n      }\r\n    },\r\n    {\r\n      "name": "clang-debug-x64",\r\n      "inherits": "ninja-debug-x64",\r\n      "cacheVariables": {\r\n        "CMAKE_C_COMPILER": "clang",\r\n        "CMAKE_CXX_COMPILER": "clang++"\r\n      }\r\n    }\r\n  ],\r\n  "buildPresets": [\r\n    {\r\n      "name": "gcc-build-debug-arm64",\r\n      "configurePreset": "gcc-debug-arm64"\r\n    },\r\n    {\r\n      "name": "clang-build-debug-arm64",\r\n      "configurePreset": "clang-debug-arm64"\r\n    },\r\n    {\r\n      "name": "clang-build-debug-x64",\r\n      "configurePreset": "clang-debug-x64"\r\n    }\r\n  ],\r\n  "workflowPresets": [\r\n    {\r\n      "name": "gcc-debug-arm64",\r\n      "steps": [\r\n        { "type": "configure", "name": "gcc-debug-arm64" },\r\n        { "type": "build", "name": "gcc-build-debug-arm64" }\r\n      ]\r\n    },\r\n    {\r\n      "name": "clang-debug-arm64",\r\n      "steps": [\r\n        { "type": "configure", "name": "clang-debug-arm64" },\r\n        { "type": "build", "name": "clang-build-debug-arm64" }\r\n      ]\r\n    },\r\n    {\r\n      "name": "clang-debug-x64",\r\n      "steps": [\r\n        { "type": "configure", "name": "clang-debug-x64" },\r\n        { "type": "build", "name": "clang-build-debug-x64" }\r\n      ]\r\n    }\r\n  ]\r\n}\r\n```\r\n\r\nThey are then used like so:\r\nConfigure + Build with GCC: `cmake --workflow --preset gcc-debug-arm64`\r\nConfigure + Build with Clang: `cmake --workflow --preset clang-debug-arm64`\r\nConfigure + Build with Clang (x64): `cmake --workflow --preset clang-debug-x64`\r\n\r\n</details>\r\n\r\n*Addendum: It should also now be possible to cross-compile from Windows to Unix-likes, and Unix-like to other Unix-like (e.g. Linux -> FreeBSD), however this is untested.*\r\n\r\n## Pre-Merge Requirements\r\n\r\n- [x] ~~https://github.com/dolphin-emu/ext-win-qt/pull/23 Is required for cross-compiling to work on Windows. Commit efa0923c1cb5c48886d7da1db4df30e39aeeaba1 will need to be removed from this pull request once this is done.~~ Merged as part of #14663\r\n- [ ] https://github.com/dolphin-emu/sadm/pull/204 is required for the build bots to use the new CMake presets.\r\n', 'created_at': '2026-03-16T11:57:21Z', 'updated_at': '2026-07-15T12:26:46Z', 'closed_at': None, 'merged_at': None, 'merge_commit_sha': '69c2ad54c1c92e31d83d6e411dc5dd89153c53fe', 'assignees': [], 'requested_reviewers': [], 'requested_teams': [], 'labels': [], 'milestone': None, 'draft': False, 'commits_url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/14475/commits', 'review_comments_url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/14475/comments', 'review_comment_url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/comments{/number}', 'comments_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/14475/comments', 'statuses_url': 'https://api.github.com/repos/dolphin-emu/dolphin/statuses/10a2596bc28392601c55b688715e4a65148af2c8', 'head': {'label': 'JoshuaVandaele:cmake-replaces-vs', 'ref': 'cmake-replaces-vs', 'sha': '10a2596bc28392601c55b688715e4a65148af2c8', 'user': {'login': 'JoshuaVandaele', 'id': 24195176, 'node_id': 'MDQ6VXNlcjI0MTk1MTc2', 'avatar_url': 'https://avatars.githubusercontent.com/u/24195176?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/JoshuaVandaele', 'html_url': 'https://github.com/JoshuaVandaele', 'followers_url': 'https://api.github.com/users/JoshuaVandaele/followers', 'following_url': 'https://api.github.com/users/JoshuaVandaele/following{/other_user}', 'gists_url': 'https://api.github.com/users/JoshuaVandaele/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/JoshuaVandaele/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/JoshuaVandaele/subscriptions', 'organizations_url': 'https://api.github.com/users/JoshuaVandaele/orgs', 'repos_url': 'https://api.github.com/users/JoshuaVandaele/repos', 'events_url': 'https://api.github.com/users/JoshuaVandaele/events{/privacy}', 'received_events_url': 'https://api.github.com/users/JoshuaVandaele/received_events', 'type': 'User', 'user_view_type': 'public', 'site_admin': False}, 'repo': {'id': 915253252, 'node_id': 'R_kgDONo2oBA', 'name': 'dolphin', 'full_name': 'JoshuaVandaele/dolphin', 'private': False, 'owner': {'login': 'JoshuaVandaele', 'id': 24195176, 'node_id': 'MDQ6VXNlcjI0MTk1MTc2', 'avatar_url': 'https://avatars.githubusercontent.com/u/24195176?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/JoshuaVandaele', 'html_url': 'https://github.com/JoshuaVandaele', 'followers_url': 'https://api.github.com/users/JoshuaVandaele/followers', 'following_url': 'https://api.github.com/users/JoshuaVandaele/following{/other_user}', 'gists_url': 'https://api.github.com/users/JoshuaVandaele/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/JoshuaVandaele/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/JoshuaVandaele/subscriptions', 'organizations_url': 'https://api.github.com/users/JoshuaVandaele/orgs', 'repos_url': 'https://api.github.com/users/JoshuaVandaele/repos', 'events_url': 'https://api.github.com/users/JoshuaVandaele/events{/privacy}', 'received_events_url': 'https://api.github.com/users/JoshuaVandaele/received_events', 'type': 'User', 'user_view_type': 'public', 'site_admin': False}, 'html_url': 'https://github.com/JoshuaVandaele/dolphin', 'description': 'Dolphin is a GameCube / Wii emulator, allowing you to play games for these two platforms on PC with improvements.', 'fork': True, 'url': 'https://api.github.com/repos/JoshuaVandaele/dolphin', 'forks_url': 'https://api.github.com/repos/JoshuaVandaele/dolphin/forks', 'keys_url': 'https://api.github.com/repos/JoshuaVandaele/dolphin/keys{/key_id}', 'collaborators_url': 'https://api.github.com/repos/JoshuaVandaele/dolphin/collaborators{/collaborator}', 'teams_url': 'https://api.github.com/repos/JoshuaVandaele/dolphin/teams', 'hooks_url': 'https://api.github.com/repos/JoshuaVandaele/dolphin/hooks', 'issue_events_url': 'https://api.github.com/repos/JoshuaVandaele/dolphin/issues/events{/number}', 'events_url': 'https://api.github.com/repos/JoshuaVandaele/dolphin/events', 'assignees_url': 'https://api.github.com/repos/JoshuaVandaele/dolphin/assignees{/user}', 'branches_url': 'https://api.github.com/repos/JoshuaVandaele/dolphin/branches{/branch}', 'tags_url': 'https://api.github.com/repos/JoshuaVandaele/dolphin/tags', 'blobs_url': 'https://api.github.com/repos/JoshuaVandaele/dolphin/git/blobs{/sha}', 'git_tags_url': 'https://api.github.com/repos/JoshuaVandaele/dolphin/git/tags{/sha}', 'git_refs_url': 'https://api.github.com/repos/JoshuaVandaele/dolphin/git/refs{/sha}', 'trees_url': 'https://api.github.com/repos/JoshuaVandaele/dolphin/git/trees{/sha}', 'statuses_url': 'https://api.github.com/repos/JoshuaVandaele/dolphin/statuses/{sha}', 'languages_url': 'https://api.github.com/repos/JoshuaVandaele/dolphin/languages', 'stargazers_url': 'https://api.github.com/repos/JoshuaVandaele/dolphin/stargazers', 'contributors_url': 'https://api.github.com/repos/JoshuaVandaele/dolphin/contributors', 'subscribers_url': 'https://api.github.com/repos/JoshuaVandaele/dolphin/subscribers', 'subscription_url': 'https://api.github.com/repos/JoshuaVandaele/dolphin/subscription', 'commits_url': 'https://api.github.com/repos/JoshuaVandaele/dolphin/commits{/sha}', 'git_commits_url': 'https://api.github.com/repos/JoshuaVandaele/dolphin/git/commits{/sha}', 'comments_url': 'https://api.github.com/repos/JoshuaVandaele/dolphin/comments{/number}', 'issue_comment_url': 'https://api.github.com/repos/JoshuaVandaele/dolphin/issues/comments{/number}', 'contents_url': 'https://api.github.com/repos/JoshuaVandaele/dolphin/contents/{+path}', 'compare_url': 'https://api.github.com/repos/JoshuaVandaele/dolphin/compare/{base}...{head}', 'merges_url': 'https://api.github.com/repos/JoshuaVandaele/dolphin/merges', 'archive_url': 'https://api.github.com/repos/JoshuaVandaele/dolphin/{archive_format}{/ref}', 'downloads_url': 'https://api.github.com/repos/JoshuaVandaele/dolphin/downloads', 'issues_url': 'https://api.github.com/repos/JoshuaVandaele/dolphin/issues{/number}', 'pulls_url': 'https://api.github.com/repos/JoshuaVandaele/dolphin/pulls{/number}', 'milestones_url': 'https://api.github.com/repos/JoshuaVandaele/dolphin/milestones{/number}', 'notifications_url': 'https://api.github.com/repos/JoshuaVandaele/dolphin/notifications{?since,all,participating}', 'labels_url': 'https://api.github.com/repos/JoshuaVandaele/dolphin/labels{/name}', 'releases_url': 'https://api.github.com/repos/JoshuaVandaele/dolphin/releases{/id}', 'deployments_url': 'https://api.github.com/repos/JoshuaVandaele/dolphin/deployments', 'created_at': '2025-01-11T11:19:57Z', 'updated_at': '2026-02-06T11:01:48Z', 'pushed_at': '2026-07-16T20:11:57Z', 'git_url': 'git://github.com/JoshuaVandaele/dolphin.git', 'ssh_url': 'git@github.com:JoshuaVandaele/dolphin.git', 'clone_url': 'https://github.com/JoshuaVandaele/dolphin.git', 'svn_url': 'https://github.com/JoshuaVandaele/dolphin', 'homepage': 'https://dolphin-emu.org', 'size': 517583, 'stargazers_count': 1, 'watchers_count': 1, 'language': None, 'has_issues': False, 'has_projects': True, 'has_downloads': True, 'has_wiki': True, 'has_pages': False, 'has_discussions': False, 'forks_count': 1, 'mirror_url': None, 'archived': False, 'disabled': False, 'open_issues_count': 0, 'license': None, 'allow_forking': True, 'is_template': False, 'web_commit_signoff_required': False, 'has_pull_requests': True, 'pull_request_creation_policy': 'all', 'topics': [], 'visibility': 'public', 'forks': 1, 'open_issues': 0, 'watchers': 1, 'default_branch': 'master', 'allow_squash_merge': True, 'allow_merge_commit': True, 'allow_rebase_merge': True, 'allow_auto_merge': False, 'delete_branch_on_merge': False, 'allow_update_branch': False, 'use_squash_pr_title_as_default': False, 'squash_merge_commit_message': 'COMMIT_MESSAGES', 'squash_merge_commit_title': 'COMMIT_OR_PR_TITLE', 'merge_commit_message': 'PR_TITLE', 'merge_commit_title': 'MERGE_MESSAGE'}}, 'base': {'label': 'dolphin-emu:master', 'ref': 'master', 'sha': 'fd8391a85241d1b359d662342c5c66f8f4b96d10', 'user': {'login': 'dolphin-emu', 'id': 5050316, 'node_id': 'MDEyOk9yZ2FuaXphdGlvbjUwNTAzMTY=', 'avatar_url': 'https://avatars.githubusercontent.com/u/5050316?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/dolphin-emu', 'html_url': 'https://github.com/dolphin-emu', 'followers_url': 'https://api.github.com/users/dolphin-emu/followers', 'following_url': 'https://api.github.com/users/dolphin-emu/following{/other_user}', 'gists_url': 'https://api.github.com/users/dolphin-emu/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/dolphin-emu/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/dolphin-emu/subscriptions', 'organizations_url': 'https://api.github.com/users/dolphin-emu/orgs', 'repos_url': 'https://api.github.com/users/dolphin-emu/repos', 'events_url': 'https://api.github.com/users/dolphin-emu/events{/privacy}', 'received_events_url': 'https://api.github.com/users/dolphin-emu/received_events', 'type': 'Organization', 'user_view_type': 'public', 'site_admin': False}, 'repo': {'id': 11577304, 'node_id': 'MDEwOlJlcG9zaXRvcnkxMTU3NzMwNA==', 'name': 'dolphin', 'full_name': 'dolphin-emu/dolphin', 'private': False, 'owner': {'login': 'dolphin-emu', 'id': 5050316, 'node_id': 'MDEyOk9yZ2FuaXphdGlvbjUwNTAzMTY=', 'avatar_url': 'https://avatars.githubusercontent.com/u/5050316?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/dolphin-emu', 'html_url': 'https://github.com/dolphin-emu', 'followers_url': 'https://api.github.com/users/dolphin-emu/followers', 'following_url': 'https://api.github.com/users/dolphin-emu/following{/other_user}', 'gists_url': 'https://api.github.com/users/dolphin-emu/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/dolphin-emu/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/dolphin-emu/subscriptions', 'organizations_url': 'https://api.github.com/users/dolphin-emu/orgs', 'repos_url': 'https://api.github.com/users/dolphin-emu/repos', 'events_url': 'https://api.github.com/users/dolphin-emu/events{/privacy}', 'received_events_url': 'https://api.github.com/users/dolphin-emu/received_events', 'type': 'Organization', 'user_view_type': 'public', 'site_admin': False}, 'html_url': 'https://github.com/dolphin-emu/dolphin', 'description': 'Dolphin is a GameCube / Wii emulator, allowing you to play games for these two platforms on PC with improvements.', 'fork': False, 'url': 'https://api.github.com/repos/dolphin-emu/dolphin', 'forks_url': 'https://api.github.com/repos/dolphin-emu/dolphin/forks', 'keys_url': 'https://api.github.com/repos/dolphin-emu/dolphin/keys{/key_id}', 'collaborators_url': 'https://api.github.com/repos/dolphin-emu/dolphin/collaborators{/collaborator}', 'teams_url': 'https://api.github.com/repos/dolphin-emu/dolphin/teams', 'hooks_url': 'https://api.github.com/repos/dolphin-emu/dolphin/hooks', 'issue_events_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/events{/number}', 'events_url': 'https://api.github.com/repos/dolphin-emu/dolphin/events', 'assignees_url': 'https://api.github.com/repos/dolphin-emu/dolphin/assignees{/user}', 'branches_url': 'https://api.github.com/repos/dolphin-emu/dolphin/branches{/branch}', 'tags_url': 'https://api.github.com/repos/dolphin-emu/dolphin/tags', 'blobs_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/blobs{/sha}', 'git_tags_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/tags{/sha}', 'git_refs_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/refs{/sha}', 'trees_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/trees{/sha}', 'statuses_url': 'https://api.github.com/repos/dolphin-emu/dolphin/statuses/{sha}', 'languages_url': 'https://api.github.com/repos/dolphin-emu/dolphin/languages', 'stargazers_url': 'https://api.github.com/repos/dolphin-emu/dolphin/stargazers', 'contributors_url': 'https://api.github.com/repos/dolphin-emu/dolphin/contributors', 'subscribers_url': 'https://api.github.com/repos/dolphin-emu/dolphin/subscribers', 'subscription_url': 'https://api.github.com/repos/dolphin-emu/dolphin/subscription', 'commits_url': 'https://api.github.com/repos/dolphin-emu/dolphin/commits{/sha}', 'git_commits_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/commits{/sha}', 'comments_url': 'https://api.github.com/repos/dolphin-emu/dolphin/comments{/number}', 'issue_comment_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/comments{/number}', 'contents_url': 'https://api.github.com/repos/dolphin-emu/dolphin/contents/{+path}', 'compare_url': 'https://api.github.com/repos/dolphin-emu/dolphin/compare/{base}...{head}', 'merges_url': 'https://api.github.com/repos/dolphin-emu/dolphin/merges', 'archive_url': 'https://api.github.com/repos/dolphin-emu/dolphin/{archive_format}{/ref}', 'downloads_url': 'https://api.github.com/repos/dolphin-emu/dolphin/downloads', 'issues_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues{/number}', 'pulls_url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls{/number}', 'milestones_url': 'https://api.github.com/repos/dolphin-emu/dolphin/milestones{/number}', 'notifications_url': 'https://api.github.com/repos/dolphin-emu/dolphin/notifications{?since,all,participating}', 'labels_url': 'https://api.github.com/repos/dolphin-emu/dolphin/labels{/name}', 'releases_url': 'https://api.github.com/repos/dolphin-emu/dolphin/releases{/id}', 'deployments_url': 'https://api.github.com/repos/dolphin-emu/dolphin/deployments', 'created_at': '2013-07-22T09:07:57Z', 'updated_at': '2026-07-18T18:44:16Z', 'pushed_at': '2026-07-18T10:34:54Z', 'git_url': 'git://github.com/dolphin-emu/dolphin.git', 'ssh_url': 'git@github.com:dolphin-emu/dolphin.git', 'clone_url': 'https://github.com/dolphin-emu/dolphin.git', 'svn_url': 'https://github.com/dolphin-emu/dolphin', 'homepage': 'https://dolphin-emu.org', 'size': 558448, 'stargazers_count': 15272, 'watchers_count': 15272, 'language': 'C++', 'has_issues': False, 'has_projects': False, 'has_downloads': True, 'has_wiki': True, 'has_pages': False, 'has_discussions': False, 'forks_count': 3162, 'mirror_url': None, 'archived': False, 'disabled': False, 'open_issues_count': 446, 'license': {'key': 'other', 'name': 'Other', 'spdx_id': 'NOASSERTION', 'url': None, 'node_id': 'MDc6TGljZW5zZTA='}, 'allow_forking': True, 'is_template': False, 'web_commit_signoff_required': False, 'has_pull_requests': True, 'pull_request_creation_policy': 'all', 'topics': ['cpp', 'emulation', 'emulator', 'gamecube', 'wii'], 'visibility': 'public', 'forks': 3162, 'open_issues': 446, 'watchers': 15272, 'default_branch': 'master', 'allow_squash_merge': False, 'allow_merge_commit': True, 'allow_rebase_merge': False, 'allow_auto_merge': False, 'delete_branch_on_merge': False, 'allow_update_branch': False, 'use_squash_pr_title_as_default': False, 'squash_merge_commit_message': 'COMMIT_MESSAGES', 'squash_merge_commit_title': 'COMMIT_OR_PR_TITLE', 'merge_commit_message': 'PR_TITLE', 'merge_commit_title': 'MERGE_MESSAGE'}}, '_links': {'self': {'href': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/14475'}, 'html': {'href': 'https://github.com/dolphin-emu/dolphin/pull/14475'}, 'issue': {'href': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/14475'}, 'comments': {'href': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/14475/comments'}, 'review_comments': {'href': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/14475/comments'}, 'review_comment': {'href': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/comments{/number}'}, 'commits': {'href': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/14475/commits'}, 'statuses': {'href': 'https://api.github.com/repos/dolphin-emu/dolphin/statuses/10a2596bc28392601c55b688715e4a65148af2c8'}}, 'author_association': 'CONTRIBUTOR', 'auto_merge': None, 'assignee': None, 'active_lock_reason': None}, 'repository': {'id': 11577304, 'node_id': 'MDEwOlJlcG9zaXRvcnkxMTU3NzMwNA==', 'name': 'dolphin', 'full_name': 'dolphin-emu/dolphin', 'private': False, 'owner': {'login': 'dolphin-emu', 'id': 5050316, 'node_id': 'MDEyOk9yZ2FuaXphdGlvbjUwNTAzMTY=', 'avatar_url': 'https://avatars.githubusercontent.com/u/5050316?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/dolphin-emu', 'html_url': 'https://github.com/dolphin-emu', 'followers_url': 'https://api.github.com/users/dolphin-emu/followers', 'following_url': 'https://api.github.com/users/dolphin-emu/following{/other_user}', 'gists_url': 'https://api.github.com/users/dolphin-emu/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/dolphin-emu/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/dolphin-emu/subscriptions', 'organizations_url': 'https://api.github.com/users/dolphin-emu/orgs', 'repos_url': 'https://api.github.com/users/dolphin-emu/repos', 'events_url': 'https://api.github.com/users/dolphin-emu/events{/privacy}', 'received_events_url': 'https://api.github.com/users/dolphin-emu/received_events', 'type': 'Organization', 'user_view_type': 'public', 'site_admin': False}, 'html_url': 'https://github.com/dolphin-emu/dolphin', 'description': 'Dolphin is a GameCube / Wii emulator, allowing you to play games for these two platforms on PC with improvements.', 'fork': False, 'url': 'https://api.github.com/repos/dolphin-emu/dolphin', 'forks_url': 'https://api.github.com/repos/dolphin-emu/dolphin/forks', 'keys_url': 'https://api.github.com/repos/dolphin-emu/dolphin/keys{/key_id}', 'collaborators_url': 'https://api.github.com/repos/dolphin-emu/dolphin/collaborators{/collaborator}', 'teams_url': 'https://api.github.com/repos/dolphin-emu/dolphin/teams', 'hooks_url': 'https://api.github.com/repos/dolphin-emu/dolphin/hooks', 'issue_events_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/events{/number}', 'events_url': 'https://api.github.com/repos/dolphin-emu/dolphin/events', 'assignees_url': 'https://api.github.com/repos/dolphin-emu/dolphin/assignees{/user}', 'branches_url': 'https://api.github.com/repos/dolphin-emu/dolphin/branches{/branch}', 'tags_url': 'https://api.github.com/repos/dolphin-emu/dolphin/tags', 'blobs_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/blobs{/sha}', 'git_tags_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/tags{/sha}', 'git_refs_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/refs{/sha}', 'trees_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/trees{/sha}', 'statuses_url': 'https://api.github.com/repos/dolphin-emu/dolphin/statuses/{sha}', 'languages_url': 'https://api.github.com/repos/dolphin-emu/dolphin/languages', 'stargazers_url': 'https://api.github.com/repos/dolphin-emu/dolphin/stargazers', 'contributors_url': 'https://api.github.com/repos/dolphin-emu/dolphin/contributors', 'subscribers_url': 'https://api.github.com/repos/dolphin-emu/dolphin/subscribers', 'subscription_url': 'https://api.github.com/repos/dolphin-emu/dolphin/subscription', 'commits_url': 'https://api.github.com/repos/dolphin-emu/dolphin/commits{/sha}', 'git_commits_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/commits{/sha}', 'comments_url': 'https://api.github.com/repos/dolphin-emu/dolphin/comments{/number}', 'issue_comment_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/comments{/number}', 'contents_url': 'https://api.github.com/repos/dolphin-emu/dolphin/contents/{+path}', 'compare_url': 'https://api.github.com/repos/dolphin-emu/dolphin/compare/{base}...{head}', 'merges_url': 'https://api.github.com/repos/dolphin-emu/dolphin/merges', 'archive_url': 'https://api.github.com/repos/dolphin-emu/dolphin/{archive_format}{/ref}', 'downloads_url': 'https://api.github.com/repos/dolphin-emu/dolphin/downloads', 'issues_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues{/number}', 'pulls_url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls{/number}', 'milestones_url': 'https://api.github.com/repos/dolphin-emu/dolphin/milestones{/number}', 'notifications_url': 'https://api.github.com/repos/dolphin-emu/dolphin/notifications{?since,all,participating}', 'labels_url': 'https://api.github.com/repos/dolphin-emu/dolphin/labels{/name}', 'releases_url': 'https://api.github.com/repos/dolphin-emu/dolphin/releases{/id}', 'deployments_url': 'https://api.github.com/repos/dolphin-emu/dolphin/deployments', 'created_at': '2013-07-22T09:07:57Z', 'updated_at': '2026-07-18T18:44:16Z', 'pushed_at': '2026-07-18T10:34:54Z', 'git_url': 'git://github.com/dolphin-emu/dolphin.git', 'ssh_url': 'git@github.com:dolphin-emu/dolphin.git', 'clone_url': 'https://github.com/dolphin-emu/dolphin.git', 'svn_url': 'https://github.com/dolphin-emu/dolphin', 'homepage': 'https://dolphin-emu.org', 'size': 558448, 'stargazers_count': 15272, 'watchers_count': 15272, 'language': 'C++', 'has_issues': False, 'has_projects': False, 'has_downloads': True, 'has_wiki': True, 'has_pages': False, 'has_discussions': False, 'forks_count': 3162, 'mirror_url': None, 'archived': False, 'disabled': False, 'open_issues_count': 446, 'license': {'key': 'other', 'name': 'Other', 'spdx_id': 'NOASSERTION', 'url': None, 'node_id': 'MDc6TGljZW5zZTA='}, 'allow_forking': True, 'is_template': False, 'web_commit_signoff_required': False, 'has_pull_requests': True, 'pull_request_creation_policy': 'all', 'topics': ['cpp', 'emulation', 'emulator', 'gamecube', 'wii'], 'visibility': 'public', 'forks': 3162, 'open_issues': 446, 'watchers': 15272, 'default_branch': 'master', 'custom_properties': {}}, 'organization': {'login': 'dolphin-emu', 'id': 5050316, 'node_id': 'MDEyOk9yZ2FuaXphdGlvbjUwNTAzMTY=', 'url': 'https://api.github.com/orgs/dolphin-emu', 'repos_url': 'https://api.github.com/orgs/dolphin-emu/repos', 'events_url': 'https://api.github.com/orgs/dolphin-emu/events', 'hooks_url': 'https://api.github.com/orgs/dolphin-emu/hooks', 'issues_url': 'https://api.github.com/orgs/dolphin-emu/issues', 'members_url': 'https://api.github.com/orgs/dolphin-emu/members{/member}', 'public_members_url': 'https://api.github.com/orgs/dolphin-emu/public_members{/member}', 'avatar_url': 'https://avatars.githubusercontent.com/u/5050316?v=4', 'description': ''}, 'sender': {'login': 'phire', 'id': 138484, 'node_id': 'MDQ6VXNlcjEzODQ4NA==', 'avatar_url': 'https://avatars.githubusercontent.com/u/138484?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/phire', 'html_url': 'https://github.com/phire', 'followers_url': 'https://api.github.com/users/phire/followers', 'following_url': 'https://api.github.com/users/phire/following{/other_user}', 'gists_url': 'https://api.github.com/users/phire/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/phire/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/phire/subscriptions', 'organizations_url': 'https://api.github.com/users/phire/orgs', 'repos_url': 'https://api.github.com/users/phire/repos', 'events_url': 'https://api.github.com/users/phire/events{/privacy}', 'received_events_url': 'https://api.github.com/users/phire/received_events', 'type': 'User', 'user_view_type': 'public', 'site_admin': False}, 'installation': {'id': 35437981, 'node_id': 'MDIzOkludGVncmF0aW9uSW5zdGFsbGF0aW9uMzU0Mzc5ODE='}}, 'type': 'raw_gh_hook'}
2026-07-18T22:51:01.273206	{'source': 'webserver', 'gh_type': 'pull_request_review', 'raw': {'action': 'submitted', 'review': {'id': 4729430995, 'node_id': 'PRR_kwDOALAO3s8AAAABGeVj0w', 'user': {'login': 'phire', 'id': 138484, 'node_id': 'MDQ6VXNlcjEzODQ4NA==', 'avatar_url': 'https://avatars.githubusercontent.com/u/138484?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/phire', 'html_url': 'https://github.com/phire', 'followers_url': 'https://api.github.com/users/phire/followers', 'following_url': 'https://api.github.com/users/phire/following{/other_user}', 'gists_url': 'https://api.github.com/users/phire/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/phire/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/phire/subscriptions', 'organizations_url': 'https://api.github.com/users/phire/orgs', 'repos_url': 'https://api.github.com/users/phire/repos', 'events_url': 'https://api.github.com/users/phire/events{/privacy}', 'received_events_url': 'https://api.github.com/users/phire/received_events', 'type': 'User', 'user_view_type': 'public', 'site_admin': False}, 'body': "But if nobody else shares my concerns, I don't object. ", 'commit_id': 'b30d4c348d6543052f580f01308990aceaffbcbd', 'state': 'approved', 'html_url': 'https://github.com/dolphin-emu/sadm/pull/204#pullrequestreview-4729430995', 'pull_request_url': 'https://api.github.com/repos/dolphin-emu/sadm/pulls/204', '_links': {'html': {'href': 'https://github.com/dolphin-emu/sadm/pull/204#pullrequestreview-4729430995'}, 'pull_request': {'href': 'https://api.github.com/repos/dolphin-emu/sadm/pulls/204'}}, 'submitted_at': '2026-07-18T22:50:59Z', 'updated_at': '2026-07-18T22:50:59Z', 'author_association': 'MEMBER'}, 'pull_request': {'url': 'https://api.github.com/repos/dolphin-emu/sadm/pulls/204', 'id': 3404081972, 'node_id': 'PR_kwDOALAO3s7K5is0', 'html_url': 'https://github.com/dolphin-emu/sadm/pull/204', 'diff_url': 'https://github.com/dolphin-emu/sadm/pull/204.diff', 'patch_url': 'https://github.com/dolphin-emu/sadm/pull/204.patch', 'issue_url': 'https://api.github.com/repos/dolphin-emu/sadm/issues/204', 'number': 204, 'state': 'open', 'locked': False, 'title': 'Update buildbot configuration to use new CMake presets', 'user': {'login': 'JoshuaVandaele', 'id': 24195176, 'node_id': 'MDQ6VXNlcjI0MTk1MTc2', 'avatar_url': 'https://avatars.githubusercontent.com/u/24195176?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/JoshuaVandaele', 'html_url': 'https://github.com/JoshuaVandaele', 'followers_url': 'https://api.github.com/users/JoshuaVandaele/followers', 'following_url': 'https://api.github.com/users/JoshuaVandaele/following{/other_user}', 'gists_url': 'https://api.github.com/users/JoshuaVandaele/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/JoshuaVandaele/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/JoshuaVandaele/subscriptions', 'organizations_url': 'https://api.github.com/users/JoshuaVandaele/orgs', 'repos_url': 'https://api.github.com/users/JoshuaVandaele/repos', 'events_url': 'https://api.github.com/users/JoshuaVandaele/events{/privacy}', 'received_events_url': 'https://api.github.com/users/JoshuaVandaele/received_events', 'type': 'User', 'user_view_type': 'public', 'site_admin': False}, 'body': 'From https://github.com/dolphin-emu/dolphin/pull/14475', 'created_at': '2026-03-16T11:57:11Z', 'updated_at': '2026-07-18T22:41:08Z', 'closed_at': None, 'merged_at': None, 'merge_commit_sha': '8c79dbd854765a9d95e889a98a8d7718f846cefe', 'assignees': [], 'requested_reviewers': [], 'requested_teams': [], 'labels': [], 'milestone': None, 'draft': False, 'commits_url': 'https://api.github.com/repos/dolphin-emu/sadm/pulls/204/commits', 'review_comments_url': 'https://api.github.com/repos/dolphin-emu/sadm/pulls/204/comments', 'review_comment_url': 'https://api.github.com/repos/dolphin-emu/sadm/pulls/comments{/number}', 'comments_url': 'https://api.github.com/repos/dolphin-emu/sadm/issues/204/comments', 'statuses_url': 'https://api.github.com/repos/dolphin-emu/sadm/statuses/b30d4c348d6543052f580f01308990aceaffbcbd', 'head': {'label': 'JoshuaVandaele:cmake-update', 'ref': 'cmake-update', 'sha': 'b30d4c348d6543052f580f01308990aceaffbcbd', 'user': {'login': 'JoshuaVandaele', 'id': 24195176, 'node_id': 'MDQ6VXNlcjI0MTk1MTc2', 'avatar_url': 'https://avatars.githubusercontent.com/u/24195176?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/JoshuaVandaele', 'html_url': 'https://github.com/JoshuaVandaele', 'followers_url': 'https://api.github.com/users/JoshuaVandaele/followers', 'following_url': 'https://api.github.com/users/JoshuaVandaele/following{/other_user}', 'gists_url': 'https://api.github.com/users/JoshuaVandaele/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/JoshuaVandaele/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/JoshuaVandaele/subscriptions', 'organizations_url': 'https://api.github.com/users/JoshuaVandaele/orgs', 'repos_url': 'https://api.github.com/users/JoshuaVandaele/repos', 'events_url': 'https://api.github.com/users/JoshuaVandaele/events{/privacy}', 'received_events_url': 'https://api.github.com/users/JoshuaVandaele/received_events', 'type': 'User', 'user_view_type': 'public', 'site_admin': False}, 'repo': {'id': 949957179, 'node_id': 'R_kgDOOJ8yOw', 'name': 'sadm', 'full_name': 'JoshuaVandaele/sadm', 'private': False, 'owner': {'login': 'JoshuaVandaele', 'id': 24195176, 'node_id': 'MDQ6VXNlcjI0MTk1MTc2', 'avatar_url': 'https://avatars.githubusercontent.com/u/24195176?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/JoshuaVandaele', 'html_url': 'https://github.com/JoshuaVandaele', 'followers_url': 'https://api.github.com/users/JoshuaVandaele/followers', 'following_url': 'https://api.github.com/users/JoshuaVandaele/following{/other_user}', 'gists_url': 'https://api.github.com/users/JoshuaVandaele/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/JoshuaVandaele/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/JoshuaVandaele/subscriptions', 'organizations_url': 'https://api.github.com/users/JoshuaVandaele/orgs', 'repos_url': 'https://api.github.com/users/JoshuaVandaele/repos', 'events_url': 'https://api.github.com/users/JoshuaVandaele/events{/privacy}', 'received_events_url': 'https://api.github.com/users/JoshuaVandaele/received_events', 'type': 'User', 'user_view_type': 'public', 'site_admin': False}, 'html_url': 'https://github.com/JoshuaVandaele/sadm', 'description': 'Scripts and configurations for the Dolphin Emulator infrastructure', 'fork': True, 'url': 'https://api.github.com/repos/JoshuaVandaele/sadm', 'forks_url': 'https://api.github.com/repos/JoshuaVandaele/sadm/forks', 'keys_url': 'https://api.github.com/repos/JoshuaVandaele/sadm/keys{/key_id}', 'collaborators_url': 'https://api.github.com/repos/JoshuaVandaele/sadm/collaborators{/collaborator}', 'teams_url': 'https://api.github.com/repos/JoshuaVandaele/sadm/teams', 'hooks_url': 'https://api.github.com/repos/JoshuaVandaele/sadm/hooks', 'issue_events_url': 'https://api.github.com/repos/JoshuaVandaele/sadm/issues/events{/number}', 'events_url': 'https://api.github.com/repos/JoshuaVandaele/sadm/events', 'assignees_url': 'https://api.github.com/repos/JoshuaVandaele/sadm/assignees{/user}', 'branches_url': 'https://api.github.com/repos/JoshuaVandaele/sadm/branches{/branch}', 'tags_url': 'https://api.github.com/repos/JoshuaVandaele/sadm/tags', 'blobs_url': 'https://api.github.com/repos/JoshuaVandaele/sadm/git/blobs{/sha}', 'git_tags_url': 'https://api.github.com/repos/JoshuaVandaele/sadm/git/tags{/sha}', 'git_refs_url': 'https://api.github.com/repos/JoshuaVandaele/sadm/git/refs{/sha}', 'trees_url': 'https://api.github.com/repos/JoshuaVandaele/sadm/git/trees{/sha}', 'statuses_url': 'https://api.github.com/repos/JoshuaVandaele/sadm/statuses/{sha}', 'languages_url': 'https://api.github.com/repos/JoshuaVandaele/sadm/languages', 'stargazers_url': 'https://api.github.com/repos/JoshuaVandaele/sadm/stargazers', 'contributors_url': 'https://api.github.com/repos/JoshuaVandaele/sadm/contributors', 'subscribers_url': 'https://api.github.com/repos/JoshuaVandaele/sadm/subscribers', 'subscription_url': 'https://api.github.com/repos/JoshuaVandaele/sadm/subscription', 'commits_url': 'https://api.github.com/repos/JoshuaVandaele/sadm/commits{/sha}', 'git_commits_url': 'https://api.github.com/repos/JoshuaVandaele/sadm/git/commits{/sha}', 'comments_url': 'https://api.github.com/repos/JoshuaVandaele/sadm/comments{/number}', 'issue_comment_url': 'https://api.github.com/repos/JoshuaVandaele/sadm/issues/comments{/number}', 'contents_url': 'https://api.github.com/repos/JoshuaVandaele/sadm/contents/{+path}', 'compare_url': 'https://api.github.com/repos/JoshuaVandaele/sadm/compare/{base}...{head}', 'merges_url': 'https://api.github.com/repos/JoshuaVandaele/sadm/merges', 'archive_url': 'https://api.github.com/repos/JoshuaVandaele/sadm/{archive_format}{/ref}', 'downloads_url': 'https://api.github.com/repos/JoshuaVandaele/sadm/downloads', 'issues_url': 'https://api.github.com/repos/JoshuaVandaele/sadm/issues{/number}', 'pulls_url': 'https://api.github.com/repos/JoshuaVandaele/sadm/pulls{/number}', 'milestones_url': 'https://api.github.com/repos/JoshuaVandaele/sadm/milestones{/number}', 'notifications_url': 'https://api.github.com/repos/JoshuaVandaele/sadm/notifications{?since,all,participating}', 'labels_url': 'https://api.github.com/repos/JoshuaVandaele/sadm/labels{/name}', 'releases_url': 'https://api.github.com/repos/JoshuaVandaele/sadm/releases{/id}', 'deployments_url': 'https://api.github.com/repos/JoshuaVandaele/sadm/deployments', 'created_at': '2025-03-17T12:07:35Z', 'updated_at': '2025-03-17T12:07:35Z', 'pushed_at': '2026-05-03T18:57:23Z', 'git_url': 'git://github.com/JoshuaVandaele/sadm.git', 'ssh_url': 'git@github.com:JoshuaVandaele/sadm.git', 'clone_url': 'https://github.com/JoshuaVandaele/sadm.git', 'svn_url': 'https://github.com/JoshuaVandaele/sadm', 'homepage': '', 'size': 635, 'stargazers_count': 0, 'watchers_count': 0, 'language': None, 'has_issues': False, 'has_projects': True, 'has_downloads': True, 'has_wiki': True, 'has_pages': False, 'has_discussions': False, 'forks_count': 0, 'mirror_url': None, 'archived': False, 'disabled': False, 'open_issues_count': 0, 'license': {'key': 'mit', 'name': 'MIT License', 'spdx_id': 'MIT', 'url': 'https://api.github.com/licenses/mit', 'node_id': 'MDc6TGljZW5zZTEz'}, 'allow_forking': True, 'is_template': False, 'web_commit_signoff_required': False, 'has_pull_requests': True, 'pull_request_creation_policy': 'all', 'topics': [], 'visibility': 'public', 'forks': 0, 'open_issues': 0, 'watchers': 0, 'default_branch': 'master', 'allow_squash_merge': True, 'allow_merge_commit': True, 'allow_rebase_merge': True, 'allow_auto_merge': False, 'delete_branch_on_merge': False, 'allow_update_branch': False, 'use_squash_pr_title_as_default': False, 'squash_merge_commit_message': 'COMMIT_MESSAGES', 'squash_merge_commit_title': 'COMMIT_OR_PR_TITLE', 'merge_commit_message': 'PR_TITLE', 'merge_commit_title': 'MERGE_MESSAGE'}}, 'base': {'label': 'dolphin-emu:master', 'ref': 'master', 'sha': '49b6a7388c001efe5aa605daf56e965c8840528a', 'user': {'login': 'dolphin-emu', 'id': 5050316, 'node_id': 'MDEyOk9yZ2FuaXphdGlvbjUwNTAzMTY=', 'avatar_url': 'https://avatars.githubusercontent.com/u/5050316?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/dolphin-emu', 'html_url': 'https://github.com/dolphin-emu', 'followers_url': 'https://api.github.com/users/dolphin-emu/followers', 'following_url': 'https://api.github.com/users/dolphin-emu/following{/other_user}', 'gists_url': 'https://api.github.com/users/dolphin-emu/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/dolphin-emu/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/dolphin-emu/subscriptions', 'organizations_url': 'https://api.github.com/users/dolphin-emu/orgs', 'repos_url': 'https://api.github.com/users/dolphin-emu/repos', 'events_url': 'https://api.github.com/users/dolphin-emu/events{/privacy}', 'received_events_url': 'https://api.github.com/users/dolphin-emu/received_events', 'type': 'Organization', 'user_view_type': 'public', 'site_admin': False}, 'repo': {'id': 11538142, 'node_id': 'MDEwOlJlcG9zaXRvcnkxMTUzODE0Mg==', 'name': 'sadm', 'full_name': 'dolphin-emu/sadm', 'private': False, 'owner': {'login': 'dolphin-emu', 'id': 5050316, 'node_id': 'MDEyOk9yZ2FuaXphdGlvbjUwNTAzMTY=', 'avatar_url': 'https://avatars.githubusercontent.com/u/5050316?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/dolphin-emu', 'html_url': 'https://github.com/dolphin-emu', 'followers_url': 'https://api.github.com/users/dolphin-emu/followers', 'following_url': 'https://api.github.com/users/dolphin-emu/following{/other_user}', 'gists_url': 'https://api.github.com/users/dolphin-emu/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/dolphin-emu/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/dolphin-emu/subscriptions', 'organizations_url': 'https://api.github.com/users/dolphin-emu/orgs', 'repos_url': 'https://api.github.com/users/dolphin-emu/repos', 'events_url': 'https://api.github.com/users/dolphin-emu/events{/privacy}', 'received_events_url': 'https://api.github.com/users/dolphin-emu/received_events', 'type': 'Organization', 'user_view_type': 'public', 'site_admin': False}, 'html_url': 'https://github.com/dolphin-emu/sadm', 'description': 'Scripts and configurations for the Dolphin Emulator infrastructure', 'fork': False, 'url': 'https://api.github.com/repos/dolphin-emu/sadm', 'forks_url': 'https://api.github.com/repos/dolphin-emu/sadm/forks', 'keys_url': 'https://api.github.com/repos/dolphin-emu/sadm/keys{/key_id}', 'collaborators_url': 'https://api.github.com/repos/dolphin-emu/sadm/collaborators{/collaborator}', 'teams_url': 'https://api.github.com/repos/dolphin-emu/sadm/teams', 'hooks_url': 'https://api.github.com/repos/dolphin-emu/sadm/hooks', 'issue_events_url': 'https://api.github.com/repos/dolphin-emu/sadm/issues/events{/number}', 'events_url': 'https://api.github.com/repos/dolphin-emu/sadm/events', 'assignees_url': 'https://api.github.com/repos/dolphin-emu/sadm/assignees{/user}', 'branches_url': 'https://api.github.com/repos/dolphin-emu/sadm/branches{/branch}', 'tags_url': 'https://api.github.com/repos/dolphin-emu/sadm/tags', 'blobs_url': 'https://api.github.com/repos/dolphin-emu/sadm/git/blobs{/sha}', 'git_tags_url': 'https://api.github.com/repos/dolphin-emu/sadm/git/tags{/sha}', 'git_refs_url': 'https://api.github.com/repos/dolphin-emu/sadm/git/refs{/sha}', 'trees_url': 'https://api.github.com/repos/dolphin-emu/sadm/git/trees{/sha}', 'statuses_url': 'https://api.github.com/repos/dolphin-emu/sadm/statuses/{sha}', 'languages_url': 'https://api.github.com/repos/dolphin-emu/sadm/languages', 'stargazers_url': 'https://api.github.com/repos/dolphin-emu/sadm/stargazers', 'contributors_url': 'https://api.github.com/repos/dolphin-emu/sadm/contributors', 'subscribers_url': 'https://api.github.com/repos/dolphin-emu/sadm/subscribers', 'subscription_url': 'https://api.github.com/repos/dolphin-emu/sadm/subscription', 'commits_url': 'https://api.github.com/repos/dolphin-emu/sadm/commits{/sha}', 'git_commits_url': 'https://api.github.com/repos/dolphin-emu/sadm/git/commits{/sha}', 'comments_url': 'https://api.github.com/repos/dolphin-emu/sadm/comments{/number}', 'issue_comment_url': 'https://api.github.com/repos/dolphin-emu/sadm/issues/comments{/number}', 'contents_url': 'https://api.github.com/repos/dolphin-emu/sadm/contents/{+path}', 'compare_url': 'https://api.github.com/repos/dolphin-emu/sadm/compare/{base}...{head}', 'merges_url': 'https://api.github.com/repos/dolphin-emu/sadm/merges', 'archive_url': 'https://api.github.com/repos/dolphin-emu/sadm/{archive_format}{/ref}', 'downloads_url': 'https://api.github.com/repos/dolphin-emu/sadm/downloads', 'issues_url': 'https://api.github.com/repos/dolphin-emu/sadm/issues{/number}', 'pulls_url': 'https://api.github.com/repos/dolphin-emu/sadm/pulls{/number}', 'milestones_url': 'https://api.github.com/repos/dolphin-emu/sadm/milestones{/number}', 'notifications_url': 'https://api.github.com/repos/dolphin-emu/sadm/notifications{?since,all,participating}', 'labels_url': 'https://api.github.com/repos/dolphin-emu/sadm/labels{/name}', 'releases_url': 'https://api.github.com/repos/dolphin-emu/sadm/releases{/id}', 'deployments_url': 'https://api.github.com/repos/dolphin-emu/sadm/deployments', 'created_at': '2013-07-19T22:07:05Z', 'updated_at': '2026-07-10T05:00:46Z', 'pushed_at': '2026-07-10T05:00:33Z', 'git_url': 'git://github.com/dolphin-emu/sadm.git', 'ssh_url': 'git@github.com:dolphin-emu/sadm.git', 'clone_url': 'https://github.com/dolphin-emu/sadm.git', 'svn_url': 'https://github.com/dolphin-emu/sadm', 'homepage': '', 'size': 1235, 'stargazers_count': 51, 'watchers_count': 51, 'language': 'Nix', 'has_issues': True, 'has_projects': False, 'has_downloads': True, 'has_wiki': True, 'has_pages': False, 'has_discussions': False, 'forks_count': 43, 'mirror_url': None, 'archived': False, 'disabled': False, 'open_issues_count': 4, 'license': {'key': 'mit', 'name': 'MIT License', 'spdx_id': 'MIT', 'url': 'https://api.github.com/licenses/mit', 'node_id': 'MDc6TGljZW5zZTEz'}, 'allow_forking': True, 'is_template': False, 'web_commit_signoff_required': False, 'has_pull_requests': True, 'pull_request_creation_policy': 'all', 'topics': [], 'visibility': 'public', 'forks': 43, 'open_issues': 4, 'watchers': 51, 'default_branch': 'master', 'allow_squash_merge': True, 'allow_merge_commit': True, 'allow_rebase_merge': True, 'allow_auto_merge': False, 'delete_branch_on_merge': False, 'allow_update_branch': False, 'use_squash_pr_title_as_default': False, 'squash_merge_commit_message': 'COMMIT_MESSAGES', 'squash_merge_commit_title': 'COMMIT_OR_PR_TITLE', 'merge_commit_message': 'PR_TITLE', 'merge_commit_title': 'MERGE_MESSAGE'}}, '_links': {'self': {'href': 'https://api.github.com/repos/dolphin-emu/sadm/pulls/204'}, 'html': {'href': 'https://github.com/dolphin-emu/sadm/pull/204'}, 'issue': {'href': 'https://api.github.com/repos/dolphin-emu/sadm/issues/204'}, 'comments': {'href': 'https://api.github.com/repos/dolphin-emu/sadm/issues/204/comments'}, 'review_comments': {'href': 'https://api.github.com/repos/dolphin-emu/sadm/pulls/204/comments'}, 'review_comment': {'href': 'https://api.github.com/repos/dolphin-emu/sadm/pulls/comments{/number}'}, 'commits': {'href': 'https://api.github.com/repos/dolphin-emu/sadm/pulls/204/commits'}, 'statuses': {'href': 'https://api.github.com/repos/dolphin-emu/sadm/statuses/b30d4c348d6543052f580f01308990aceaffbcbd'}}, 'author_association': 'NONE', 'auto_merge': None, 'assignee': None, 'active_lock_reason': None}, 'repository': {'id': 11538142, 'node_id': 'MDEwOlJlcG9zaXRvcnkxMTUzODE0Mg==', 'name': 'sadm', 'full_name': 'dolphin-emu/sadm', 'private': False, 'owner': {'login': 'dolphin-emu', 'id': 5050316, 'node_id': 'MDEyOk9yZ2FuaXphdGlvbjUwNTAzMTY=', 'avatar_url': 'https://avatars.githubusercontent.com/u/5050316?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/dolphin-emu', 'html_url': 'https://github.com/dolphin-emu', 'followers_url': 'https://api.github.com/users/dolphin-emu/followers', 'following_url': 'https://api.github.com/users/dolphin-emu/following{/other_user}', 'gists_url': 'https://api.github.com/users/dolphin-emu/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/dolphin-emu/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/dolphin-emu/subscriptions', 'organizations_url': 'https://api.github.com/users/dolphin-emu/orgs', 'repos_url': 'https://api.github.com/users/dolphin-emu/repos', 'events_url': 'https://api.github.com/users/dolphin-emu/events{/privacy}', 'received_events_url': 'https://api.github.com/users/dolphin-emu/received_events', 'type': 'Organization', 'user_view_type': 'public', 'site_admin': False}, 'html_url': 'https://github.com/dolphin-emu/sadm', 'description': 'Scripts and configurations for the Dolphin Emulator infrastructure', 'fork': False, 'url': 'https://api.github.com/repos/dolphin-emu/sadm', 'forks_url': 'https://api.github.com/repos/dolphin-emu/sadm/forks', 'keys_url': 'https://api.github.com/repos/dolphin-emu/sadm/keys{/key_id}', 'collaborators_url': 'https://api.github.com/repos/dolphin-emu/sadm/collaborators{/collaborator}', 'teams_url': 'https://api.github.com/repos/dolphin-emu/sadm/teams', 'hooks_url': 'https://api.github.com/repos/dolphin-emu/sadm/hooks', 'issue_events_url': 'https://api.github.com/repos/dolphin-emu/sadm/issues/events{/number}', 'events_url': 'https://api.github.com/repos/dolphin-emu/sadm/events', 'assignees_url': 'https://api.github.com/repos/dolphin-emu/sadm/assignees{/user}', 'branches_url': 'https://api.github.com/repos/dolphin-emu/sadm/branches{/branch}', 'tags_url': 'https://api.github.com/repos/dolphin-emu/sadm/tags', 'blobs_url': 'https://api.github.com/repos/dolphin-emu/sadm/git/blobs{/sha}', 'git_tags_url': 'https://api.github.com/repos/dolphin-emu/sadm/git/tags{/sha}', 'git_refs_url': 'https://api.github.com/repos/dolphin-emu/sadm/git/refs{/sha}', 'trees_url': 'https://api.github.com/repos/dolphin-emu/sadm/git/trees{/sha}', 'statuses_url': 'https://api.github.com/repos/dolphin-emu/sadm/statuses/{sha}', 'languages_url': 'https://api.github.com/repos/dolphin-emu/sadm/languages', 'stargazers_url': 'https://api.github.com/repos/dolphin-emu/sadm/stargazers', 'contributors_url': 'https://api.github.com/repos/dolphin-emu/sadm/contributors', 'subscribers_url': 'https://api.github.com/repos/dolphin-emu/sadm/subscribers', 'subscription_url': 'https://api.github.com/repos/dolphin-emu/sadm/subscription', 'commits_url': 'https://api.github.com/repos/dolphin-emu/sadm/commits{/sha}', 'git_commits_url': 'https://api.github.com/repos/dolphin-emu/sadm/git/commits{/sha}', 'comments_url': 'https://api.github.com/repos/dolphin-emu/sadm/comments{/number}', 'issue_comment_url': 'https://api.github.com/repos/dolphin-emu/sadm/issues/comments{/number}', 'contents_url': 'https://api.github.com/repos/dolphin-emu/sadm/contents/{+path}', 'compare_url': 'https://api.github.com/repos/dolphin-emu/sadm/compare/{base}...{head}', 'merges_url': 'https://api.github.com/repos/dolphin-emu/sadm/merges', 'archive_url': 'https://api.github.com/repos/dolphin-emu/sadm/{archive_format}{/ref}', 'downloads_url': 'https://api.github.com/repos/dolphin-emu/sadm/downloads', 'issues_url': 'https://api.github.com/repos/dolphin-emu/sadm/issues{/number}', 'pulls_url': 'https://api.github.com/repos/dolphin-emu/sadm/pulls{/number}', 'milestones_url': 'https://api.github.com/repos/dolphin-emu/sadm/milestones{/number}', 'notifications_url': 'https://api.github.com/repos/dolphin-emu/sadm/notifications{?since,all,participating}', 'labels_url': 'https://api.github.com/repos/dolphin-emu/sadm/labels{/name}', 'releases_url': 'https://api.github.com/repos/dolphin-emu/sadm/releases{/id}', 'deployments_url': 'https://api.github.com/repos/dolphin-emu/sadm/deployments', 'created_at': '2013-07-19T22:07:05Z', 'updated_at': '2026-07-10T05:00:46Z', 'pushed_at': '2026-07-10T05:00:33Z', 'git_url': 'git://github.com/dolphin-emu/sadm.git', 'ssh_url': 'git@github.com:dolphin-emu/sadm.git', 'clone_url': 'https://github.com/dolphin-emu/sadm.git', 'svn_url': 'https://github.com/dolphin-emu/sadm', 'homepage': '', 'size': 1235, 'stargazers_count': 51, 'watchers_count': 51, 'language': 'Nix', 'has_issues': True, 'has_projects': False, 'has_downloads': True, 'has_wiki': True, 'has_pages': False, 'has_discussions': False, 'forks_count': 43, 'mirror_url': None, 'archived': False, 'disabled': False, 'open_issues_count': 4, 'license': {'key': 'mit', 'name': 'MIT License', 'spdx_id': 'MIT', 'url': 'https://api.github.com/licenses/mit', 'node_id': 'MDc6TGljZW5zZTEz'}, 'allow_forking': True, 'is_template': False, 'web_commit_signoff_required': False, 'has_pull_requests': True, 'pull_request_creation_policy': 'all', 'topics': [], 'visibility': 'public', 'forks': 43, 'open_issues': 4, 'watchers': 51, 'default_branch': 'master', 'custom_properties': {}}, 'organization': {'login': 'dolphin-emu', 'id': 5050316, 'node_id': 'MDEyOk9yZ2FuaXphdGlvbjUwNTAzMTY=', 'url': 'https://api.github.com/orgs/dolphin-emu', 'repos_url': 'https://api.github.com/orgs/dolphin-emu/repos', 'events_url': 'https://api.github.com/orgs/dolphin-emu/events', 'hooks_url': 'https://api.github.com/orgs/dolphin-emu/hooks', 'issues_url': 'https://api.github.com/orgs/dolphin-emu/issues', 'members_url': 'https://api.github.com/orgs/dolphin-emu/members{/member}', 'public_members_url': 'https://api.github.com/orgs/dolphin-emu/public_members{/member}', 'avatar_url': 'https://avatars.githubusercontent.com/u/5050316?v=4', 'description': ''}, 'sender': {'login': 'phire', 'id': 138484, 'node_id': 'MDQ6VXNlcjEzODQ4NA==', 'avatar_url': 'https://avatars.githubusercontent.com/u/138484?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/phire', 'html_url': 'https://github.com/phire', 'followers_url': 'https://api.github.com/users/phire/followers', 'following_url': 'https://api.github.com/users/phire/following{/other_user}', 'gists_url': 'https://api.github.com/users/phire/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/phire/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/phire/subscriptions', 'organizations_url': 'https://api.github.com/users/phire/orgs', 'repos_url': 'https://api.github.com/users/phire/repos', 'events_url': 'https://api.github.com/users/phire/events{/privacy}', 'received_events_url': 'https://api.github.com/users/phire/received_events', 'type': 'User', 'user_view_type': 'public', 'site_admin': False}, 'installation': {'id': 35437981, 'node_id': 'MDIzOkludGVncmF0aW9uSW5zdGFsbGF0aW9uMzU0Mzc5ODE='}}, 'type': 'raw_gh_hook'}
2026-07-18T22:41:10.191040	{'source': 'webserver', 'gh_type': 'issue_comment', 'raw': {'action': 'created', 'issue': {'url': 'https://api.github.com/repos/dolphin-emu/sadm/issues/204', 'repository_url': 'https://api.github.com/repos/dolphin-emu/sadm', 'labels_url': 'https://api.github.com/repos/dolphin-emu/sadm/issues/204/labels{/name}', 'comments_url': 'https://api.github.com/repos/dolphin-emu/sadm/issues/204/comments', 'events_url': 'https://api.github.com/repos/dolphin-emu/sadm/issues/204/events', 'html_url': 'https://github.com/dolphin-emu/sadm/pull/204', 'id': 4082033094, 'node_id': 'PR_kwDOALAO3s7K5is0', 'number': 204, 'title': 'Update buildbot configuration to use new CMake presets', 'user': {'login': 'JoshuaVandaele', 'id': 24195176, 'node_id': 'MDQ6VXNlcjI0MTk1MTc2', 'avatar_url': 'https://avatars.githubusercontent.com/u/24195176?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/JoshuaVandaele', 'html_url': 'https://github.com/JoshuaVandaele', 'followers_url': 'https://api.github.com/users/JoshuaVandaele/followers', 'following_url': 'https://api.github.com/users/JoshuaVandaele/following{/other_user}', 'gists_url': 'https://api.github.com/users/JoshuaVandaele/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/JoshuaVandaele/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/JoshuaVandaele/subscriptions', 'organizations_url': 'https://api.github.com/users/JoshuaVandaele/orgs', 'repos_url': 'https://api.github.com/users/JoshuaVandaele/repos', 'events_url': 'https://api.github.com/users/JoshuaVandaele/events{/privacy}', 'received_events_url': 'https://api.github.com/users/JoshuaVandaele/received_events', 'type': 'User', 'user_view_type': 'public', 'site_admin': False}, 'labels': [], 'state': 'open', 'locked': False, 'assignees': [], 'milestone': None, 'comments': 1, 'created_at': '2026-03-16T11:57:11Z', 'updated_at': '2026-07-18T22:41:08Z', 'closed_at': None, 'assignee': None, 'author_association': 'NONE', 'issue_field_values': [], 'type': None, 'active_lock_reason': None, 'draft': False, 'pull_request': {'url': 'https://api.github.com/repos/dolphin-emu/sadm/pulls/204', 'html_url': 'https://github.com/dolphin-emu/sadm/pull/204', 'diff_url': 'https://github.com/dolphin-emu/sadm/pull/204.diff', 'patch_url': 'https://github.com/dolphin-emu/sadm/pull/204.patch', 'merged_at': None}, 'body': 'From https://github.com/dolphin-emu/dolphin/pull/14475', 'reactions': {'url': 'https://api.github.com/repos/dolphin-emu/sadm/issues/204/reactions', 'total_count': 0, '+1': 0, '-1': 0, 'laugh': 0, 'hooray': 0, 'confused': 0, 'heart': 0, 'rocket': 0, 'eyes': 0}, 'timeline_url': 'https://api.github.com/repos/dolphin-emu/sadm/issues/204/timeline', 'performed_via_github_app': None, 'state_reason': None}, 'comment': {'url': 'https://api.github.com/repos/dolphin-emu/sadm/issues/comments/5013205285', 'html_url': 'https://github.com/dolphin-emu/sadm/pull/204#issuecomment-5013205285', 'issue_url': 'https://api.github.com/repos/dolphin-emu/sadm/issues/204', 'id': 5013205285, 'node_id': 'IC_kwDOALAO3s8AAAABKs9xJQ', 'user': {'login': 'phire', 'id': 138484, 'node_id': 'MDQ6VXNlcjEzODQ4NA==', 'avatar_url': 'https://avatars.githubusercontent.com/u/138484?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/phire', 'html_url': 'https://github.com/phire', 'followers_url': 'https://api.github.com/users/phire/followers', 'following_url': 'https://api.github.com/users/phire/following{/other_user}', 'gists_url': 'https://api.github.com/users/phire/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/phire/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/phire/subscriptions', 'organizations_url': 'https://api.github.com/users/phire/orgs', 'repos_url': 'https://api.github.com/users/phire/repos', 'events_url': 'https://api.github.com/users/phire/events{/privacy}', 'received_events_url': 'https://api.github.com/users/phire/received_events', 'type': 'User', 'user_view_type': 'public', 'site_admin': False}, 'created_at': '2026-07-18T22:41:08Z', 'updated_at': '2026-07-18T22:41:08Z', 'body': "So, my only concern is that this wipes out the ability for the builders to build any commits older than PR 14475. \r\n\r\nIt wouldn't be that much effort to keep the old codepath around (though not trivial).\r\n\r\nThe disadvantages of not doing so is that every single open PR will be required to be rebased before it can be merged. They will merge cleanly (as long as they haven't touched any cmake/vs files), but any new commits or manual buildbot runs will fail.\r\n\r\nWhich would result in extra build failure spam in #dev-activity, needing to tell people to rebase, walking git noobs through the process of rebasing, etc. Not the biggest issue, but a little annoying. ", 'author_association': 'MEMBER', 'reactions': {'url': 'https://api.github.com/repos/dolphin-emu/sadm/issues/comments/5013205285/reactions', 'total_count': 0, '+1': 0, '-1': 0, 'laugh': 0, 'hooray': 0, 'confused': 0, 'heart': 0, 'rocket': 0, 'eyes': 0}, 'performed_via_github_app': None, 'minimized': None}, 'repository': {'id': 11538142, 'node_id': 'MDEwOlJlcG9zaXRvcnkxMTUzODE0Mg==', 'name': 'sadm', 'full_name': 'dolphin-emu/sadm', 'private': False, 'owner': {'login': 'dolphin-emu', 'id': 5050316, 'node_id': 'MDEyOk9yZ2FuaXphdGlvbjUwNTAzMTY=', 'avatar_url': 'https://avatars.githubusercontent.com/u/5050316?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/dolphin-emu', 'html_url': 'https://github.com/dolphin-emu', 'followers_url': 'https://api.github.com/users/dolphin-emu/followers', 'following_url': 'https://api.github.com/users/dolphin-emu/following{/other_user}', 'gists_url': 'https://api.github.com/users/dolphin-emu/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/dolphin-emu/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/dolphin-emu/subscriptions', 'organizations_url': 'https://api.github.com/users/dolphin-emu/orgs', 'repos_url': 'https://api.github.com/users/dolphin-emu/repos', 'events_url': 'https://api.github.com/users/dolphin-emu/events{/privacy}', 'received_events_url': 'https://api.github.com/users/dolphin-emu/received_events', 'type': 'Organization', 'user_view_type': 'public', 'site_admin': False}, 'html_url': 'https://github.com/dolphin-emu/sadm', 'description': 'Scripts and configurations for the Dolphin Emulator infrastructure', 'fork': False, 'url': 'https://api.github.com/repos/dolphin-emu/sadm', 'forks_url': 'https://api.github.com/repos/dolphin-emu/sadm/forks', 'keys_url': 'https://api.github.com/repos/dolphin-emu/sadm/keys{/key_id}', 'collaborators_url': 'https://api.github.com/repos/dolphin-emu/sadm/collaborators{/collaborator}', 'teams_url': 'https://api.github.com/repos/dolphin-emu/sadm/teams', 'hooks_url': 'https://api.github.com/repos/dolphin-emu/sadm/hooks', 'issue_events_url': 'https://api.github.com/repos/dolphin-emu/sadm/issues/events{/number}', 'events_url': 'https://api.github.com/repos/dolphin-emu/sadm/events', 'assignees_url': 'https://api.github.com/repos/dolphin-emu/sadm/assignees{/user}', 'branches_url': 'https://api.github.com/repos/dolphin-emu/sadm/branches{/branch}', 'tags_url': 'https://api.github.com/repos/dolphin-emu/sadm/tags', 'blobs_url': 'https://api.github.com/repos/dolphin-emu/sadm/git/blobs{/sha}', 'git_tags_url': 'https://api.github.com/repos/dolphin-emu/sadm/git/tags{/sha}', 'git_refs_url': 'https://api.github.com/repos/dolphin-emu/sadm/git/refs{/sha}', 'trees_url': 'https://api.github.com/repos/dolphin-emu/sadm/git/trees{/sha}', 'statuses_url': 'https://api.github.com/repos/dolphin-emu/sadm/statuses/{sha}', 'languages_url': 'https://api.github.com/repos/dolphin-emu/sadm/languages', 'stargazers_url': 'https://api.github.com/repos/dolphin-emu/sadm/stargazers', 'contributors_url': 'https://api.github.com/repos/dolphin-emu/sadm/contributors', 'subscribers_url': 'https://api.github.com/repos/dolphin-emu/sadm/subscribers', 'subscription_url': 'https://api.github.com/repos/dolphin-emu/sadm/subscription', 'commits_url': 'https://api.github.com/repos/dolphin-emu/sadm/commits{/sha}', 'git_commits_url': 'https://api.github.com/repos/dolphin-emu/sadm/git/commits{/sha}', 'comments_url': 'https://api.github.com/repos/dolphin-emu/sadm/comments{/number}', 'issue_comment_url': 'https://api.github.com/repos/dolphin-emu/sadm/issues/comments{/number}', 'contents_url': 'https://api.github.com/repos/dolphin-emu/sadm/contents/{+path}', 'compare_url': 'https://api.github.com/repos/dolphin-emu/sadm/compare/{base}...{head}', 'merges_url': 'https://api.github.com/repos/dolphin-emu/sadm/merges', 'archive_url': 'https://api.github.com/repos/dolphin-emu/sadm/{archive_format}{/ref}', 'downloads_url': 'https://api.github.com/repos/dolphin-emu/sadm/downloads', 'issues_url': 'https://api.github.com/repos/dolphin-emu/sadm/issues{/number}', 'pulls_url': 'https://api.github.com/repos/dolphin-emu/sadm/pulls{/number}', 'milestones_url': 'https://api.github.com/repos/dolphin-emu/sadm/milestones{/number}', 'notifications_url': 'https://api.github.com/repos/dolphin-emu/sadm/notifications{?since,all,participating}', 'labels_url': 'https://api.github.com/repos/dolphin-emu/sadm/labels{/name}', 'releases_url': 'https://api.github.com/repos/dolphin-emu/sadm/releases{/id}', 'deployments_url': 'https://api.github.com/repos/dolphin-emu/sadm/deployments', 'created_at': '2013-07-19T22:07:05Z', 'updated_at': '2026-07-10T05:00:46Z', 'pushed_at': '2026-07-10T05:00:33Z', 'git_url': 'git://github.com/dolphin-emu/sadm.git', 'ssh_url': 'git@github.com:dolphin-emu/sadm.git', 'clone_url': 'https://github.com/dolphin-emu/sadm.git', 'svn_url': 'https://github.com/dolphin-emu/sadm', 'homepage': '', 'size': 1235, 'stargazers_count': 51, 'watchers_count': 51, 'language': 'Nix', 'has_issues': True, 'has_projects': False, 'has_downloads': True, 'has_wiki': True, 'has_pages': False, 'has_discussions': False, 'forks_count': 43, 'mirror_url': None, 'archived': False, 'disabled': False, 'open_issues_count': 4, 'license': {'key': 'mit', 'name': 'MIT License', 'spdx_id': 'MIT', 'url': 'https://api.github.com/licenses/mit', 'node_id': 'MDc6TGljZW5zZTEz'}, 'allow_forking': True, 'is_template': False, 'web_commit_signoff_required': False, 'has_pull_requests': True, 'pull_request_creation_policy': 'all', 'topics': [], 'visibility': 'public', 'forks': 43, 'open_issues': 4, 'watchers': 51, 'default_branch': 'master', 'custom_properties': {}}, 'organization': {'login': 'dolphin-emu', 'id': 5050316, 'node_id': 'MDEyOk9yZ2FuaXphdGlvbjUwNTAzMTY=', 'url': 'https://api.github.com/orgs/dolphin-emu', 'repos_url': 'https://api.github.com/orgs/dolphin-emu/repos', 'events_url': 'https://api.github.com/orgs/dolphin-emu/events', 'hooks_url': 'https://api.github.com/orgs/dolphin-emu/hooks', 'issues_url': 'https://api.github.com/orgs/dolphin-emu/issues', 'members_url': 'https://api.github.com/orgs/dolphin-emu/members{/member}', 'public_members_url': 'https://api.github.com/orgs/dolphin-emu/public_members{/member}', 'avatar_url': 'https://avatars.githubusercontent.com/u/5050316?v=4', 'description': ''}, 'sender': {'login': 'phire', 'id': 138484, 'node_id': 'MDQ6VXNlcjEzODQ4NA==', 'avatar_url': 'https://avatars.githubusercontent.com/u/138484?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/phire', 'html_url': 'https://github.com/phire', 'followers_url': 'https://api.github.com/users/phire/followers', 'following_url': 'https://api.github.com/users/phire/following{/other_user}', 'gists_url': 'https://api.github.com/users/phire/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/phire/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/phire/subscriptions', 'organizations_url': 'https://api.github.com/users/phire/orgs', 'repos_url': 'https://api.github.com/users/phire/repos', 'events_url': 'https://api.github.com/users/phire/events{/privacy}', 'received_events_url': 'https://api.github.com/users/phire/received_events', 'type': 'User', 'user_view_type': 'public', 'site_admin': False}, 'installation': {'id': 35437981, 'node_id': 'MDIzOkludGVncmF0aW9uSW5zdGFsbGF0aW9uMzU0Mzc5ODE='}}, 'type': 'raw_gh_hook'}
2026-07-18T22:26:25.662986	{'source': 'webserver', 'gh_type': 'pull_request_review_comment', 'raw': {'action': 'created', 'comment': {'url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/comments/3609268698', 'pull_request_review_id': 4729322283, 'id': 3609268698, 'node_id': 'PRRC_kwDOALCn2M7XIRHa', 'diff_hunk': '@@ -186,7 +380,304 @@ std::unique_ptr<WbfsFileReader> WbfsFileReader::Create(File::DirectIOFile file,\n   if (!reader->IsGood())\n     reader.reset();\n \n+  if (reader && reader->m_has_nkit_header)\n+    reader->ReadPartitionInfo();\n+\n   return reader;\n }\n \n+// Converts any disc image to WBFS with an NKit v2 header for lossless round-trips.\n+// Strips disc-level junk and partition-level junk (encrypted sectors whose decrypted\n+// content is zero or LFG padding), records a junk bitmap for reconstruction.\n+// See: https://github.com/dolphin-emu/dolphin/pull/14731\n+bool ConvertToWBFS(BlobReader* infile, const std::string& infile_path,\n+                   const std::string& outfile_path, const CompressCB& callback)\n+{\n+  ASSERT(infile->GetDataSizeType() == DataSizeType::Accurate ||\n+         infile->GetDataSizeType() == DataSizeType::UpperBound);\n+\n+  File::DirectIOFile outfile(outfile_path, File::AccessMode::Write);\n+  if (!outfile.IsOpen())\n+  {\n+    PanicAlertFmtT(\n+        "Failed to open the output file \\"{0}\\".\\n"\n+        "Check that you have permissions to write the target folder and that the media can "\n+        "be written.",\n+        outfile_path);\n+    return false;\n+  }\n+\n+  const u64 disc_size = infile->GetDataSize();\n+\n+  // These match the values used by standard WBFS tools (wwt, WBFS Manager)\n+  static constexpr u8 hd_sector_shift = 9;\n+  static constexpr u8 wbfs_sector_shift = 21;\n+  static constexpr u64 hd_sector_size = 1ull << hd_sector_shift;\n+  static constexpr u64 wbfs_sector_size = 1ull << wbfs_sector_shift;\n+\n+  const u64 blocks_per_disc = (disc_size + wbfs_sector_size - 1) / wbfs_sector_size;\n+  const u64 disc_info_size =\n+      Common::AlignUp(WII_DISC_HEADER_SIZE + blocks_per_disc * sizeof(u16), hd_sector_size);\n+\n+  // Read disc header (first 256 bytes contain disc_id, disc_num, title, etc.)\n+  std::vector<u8> disc_header(WII_DISC_HEADER_SIZE, 0);\n+  if (!infile->Read(0, WII_DISC_HEADER_SIZE, disc_header.data()))\n+  {\n+    PanicAlertFmtT("Failed to read from the input file \\"{0}\\".", infile_path);\n+    return false;\n+  }\n+\n+  // Use Volume for partition info and decrypted reads\n+  struct PartitionInfo\n+  {\n+    u64 data_offset;\n+    u64 data_size;\n+    Partition partition;\n+  };\n+  std::vector<PartitionInfo> partitions;\n+\n+  std::unique_ptr<VolumeDisc> volume = CreateDisc(infile_path);\n+  if (volume)\n+  {\n+    for (const Partition& partition : volume->GetPartitions())\n+    {\n+      const std::optional<u64> data_offset =\n+          volume->ReadSwappedAndShifted(partition.offset + 0x2B8, PARTITION_NONE);\n+      const std::optional<u64> data_size =\n+          volume->ReadSwappedAndShifted(partition.offset + 0x2BC, PARTITION_NONE);\n+      if (!data_offset || !data_size)\n+        continue;\n+\n+      PartitionInfo info;\n+      info.data_offset = partition.offset + *data_offset;\n+      info.data_size = *data_size;\n+      info.partition = partition;\n+      partitions.push_back(info);\n+    }\n+  }\n+\n+  // NKit v2 gap type bitmap: 1 bit per block, MSB-first, always sized for dual-layer\n+  const u64 gap_type_blocks = (DL_DVD_SIZE + wbfs_sector_size - 1) / wbfs_sector_size;\n+  const u64 gap_type_bytes = (gap_type_blocks + 7) / 8;\n+  std::vector<u8> gap_type(gap_type_bytes, 0);\n+\n+  // Compute data_start up front so we can write sectors during the scan\n+  const u64 data_start = Common::AlignUp(hd_sector_size + disc_info_size, wbfs_sector_size);\n+  const u16 wlba_base = static_cast<u16>(data_start / wbfs_sector_size);\n+\n+  // Single pass: scan, classify, hash, and write used sectors in one loop\n+  std::vector<u8> sector_buf(wbfs_sector_size, 0);\n+  std::vector<u16> wlba_table(blocks_per_disc, 0);\n+  u16 used_count = 0;\n+\n+  // NKit v2 stores four hash digests for verification\n+  auto sha1_ctx = Common::SHA1::CreateContext();\n+  u32 crc = Common::StartCRC32();\n+  mbedtls_md5_context md5_ctx{};\n+  mbedtls_md5_init(&md5_ctx);\n+  mbedtls_md5_starts_ret(&md5_ctx);\n+  XXH64_state_t* xxh_state = XXH64_createState();\n+  XXH64_reset(xxh_state, 0);\n+\n+  for (u64 i = 0; i < blocks_per_disc; i++)\n+  {\n+    if (i % 100 == 0)\n+    {\n+      const bool was_cancelled =\n+          !callback(Common::GetStringT("Converting"),\n+                    static_cast<float>(i) / static_cast<float>(blocks_per_disc));\n+      if (was_cancelled)\n+      {\n+        XXH64_freeState(xxh_state);\n+        mbedtls_md5_free(&md5_ctx);\n+        outfile.Close();\n+        File::Delete(outfile_path);', 'path': 'Source/Core/DiscIO/WbfsBlob.cpp', 'commit_id': '24b41d58df2315831b74f76b95417f2739d02f9d', 'original_commit_id': '24b41d58df2315831b74f76b95417f2739d02f9d', 'user': {'login': 'phire', 'id': 138484, 'node_id': 'MDQ6VXNlcjEzODQ4NA==', 'avatar_url': 'https://avatars.githubusercontent.com/u/138484?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/phire', 'html_url': 'https://github.com/phire', 'followers_url': 'https://api.github.com/users/phire/followers', 'following_url': 'https://api.github.com/users/phire/following{/other_user}', 'gists_url': 'https://api.github.com/users/phire/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/phire/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/phire/subscriptions', 'organizations_url': 'https://api.github.com/users/phire/orgs', 'repos_url': 'https://api.github.com/users/phire/repos', 'events_url': 'https://api.github.com/users/phire/events{/privacy}', 'received_events_url': 'https://api.github.com/users/phire/received_events', 'type': 'User', 'user_view_type': 'public', 'site_admin': False}, 'body': 'Use `Common::ScopeGuard` to avoid this manual cleanup. ', 'created_at': '2026-07-18T21:58:40Z', 'updated_at': '2026-07-18T22:26:23Z', 'html_url': 'https://github.com/dolphin-emu/dolphin/pull/14731#discussion_r3609268698', 'pull_request_url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/14731', '_links': {'self': {'href': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/comments/3609268698'}, 'html': {'href': 'https://github.com/dolphin-emu/dolphin/pull/14731#discussion_r3609268698'}, 'pull_request': {'href': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/14731'}}, 'reactions': {'url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/comments/3609268698/reactions', 'total_count': 0, '+1': 0, '-1': 0, 'laugh': 0, 'hooray': 0, 'confused': 0, 'heart': 0, 'rocket': 0, 'eyes': 0}, 'start_line': 491, 'original_start_line': 491, 'start_side': 'RIGHT', 'line': 494, 'original_line': 494, 'side': 'RIGHT', 'author_association': 'MEMBER', 'original_position': 401, 'position': 401, 'subject_type': 'line'}, 'pull_request': {'url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/14731', 'id': 4056977334, 'node_id': 'PR_kwDOALCn2M7x0I-2', 'html_url': 'https://github.com/dolphin-emu/dolphin/pull/14731', 'diff_url': 'https://github.com/dolphin-emu/dolphin/pull/14731.diff', 'patch_url': 'https://github.com/dolphin-emu/dolphin/pull/14731.patch', 'issue_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/14731', 'number': 14731, 'state': 'open', 'locked': False, 'title': 'Convert To WBFS Support', 'user': {'login': 'thethiny', 'id': 6018214, 'node_id': 'MDQ6VXNlcjYwMTgyMTQ=', 'avatar_url': 'https://avatars.githubusercontent.com/u/6018214?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/thethiny', 'html_url': 'https://github.com/thethiny', 'followers_url': 'https://api.github.com/users/thethiny/followers', 'following_url': 'https://api.github.com/users/thethiny/following{/other_user}', 'gists_url': 'https://api.github.com/users/thethiny/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/thethiny/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/thethiny/subscriptions', 'organizations_url': 'https://api.github.com/users/thethiny/orgs', 'repos_url': 'https://api.github.com/users/thethiny/repos', 'events_url': 'https://api.github.com/users/thethiny/events{/privacy}', 'received_events_url': 'https://api.github.com/users/thethiny/received_events', 'type': 'User', 'user_view_type': 'public', 'site_admin': False}, 'body': "This PR introduces Conversion **to** WBFS support. WBFS is the format that is used by USB Loaders on a real Wii device.\r\n\r\n## Design decisions & hardcoded values\r\nThe writer uses fixed sector sizes that match what [libwbfs (the reference implementation by kwiirk)](https://github.com/kwiirk/wbfs/blob/master/libwbfs/libwbfs.c#L128-L134) computes for a standard single-layer Wii disc. These 2 hardcodes are stable and work correctly across all my testings.\r\n- HD sector shift: 9 (512 bytes)\r\n- WBFS sector shift: 21 (2 MiB)\r\nThese are not configurable via the UI. All existing WBFS tools use these values, and since the aim is to support USB Loaders then this has been tested and it is working on a real Wii.\r\n\r\nConverting from WBFS is not enabled. The existing `WbfsFileReader` reports `DataSizeType::UpperBound`, and `ShouldAllowConversion()` requires `Accurate`. I am able to support this but since it was hardcoded by the Dolphin team I thought a discussion is warranted.\r\n\r\n## Testing\r\n- Verified with DolphinTool header and DolphinTool verify\r\n- Verified with wit FILETYPE and wit DUMP (Wiimm's ISO Tools recognizes valid WBFS structure, partitions, encryption)\r\n- Tested ISO to WBFS and RVZ to WBFS conversions\r\n- Output file sizes match Wii Backup Manager when scrubbing is enabled (~0.1% difference), works when scrubbing is disabled.\r\n- Output WBFS files play correctly in Dolphin\r\n- Output WBFS files play correctly on a real Wii using USB Loader GX e25c4f3\r\n", 'created_at': '2026-07-15T01:16:25Z', 'updated_at': '2026-07-18T22:16:59Z', 'closed_at': None, 'merged_at': None, 'merge_commit_sha': '228f93416dd80eb09da834ad7852c8eaa4d9212b', 'assignees': [], 'requested_reviewers': [], 'requested_teams': [], 'labels': [], 'milestone': None, 'draft': False, 'commits_url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/14731/commits', 'review_comments_url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/14731/comments', 'review_comment_url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/comments{/number}', 'comments_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/14731/comments', 'statuses_url': 'https://api.github.com/repos/dolphin-emu/dolphin/statuses/24b41d58df2315831b74f76b95417f2739d02f9d', 'head': {'label': 'thethiny:wbfs-conversion', 'ref': 'wbfs-conversion', 'sha': '24b41d58df2315831b74f76b95417f2739d02f9d', 'user': {'login': 'thethiny', 'id': 6018214, 'node_id': 'MDQ6VXNlcjYwMTgyMTQ=', 'avatar_url': 'https://avatars.githubusercontent.com/u/6018214?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/thethiny', 'html_url': 'https://github.com/thethiny', 'followers_url': 'https://api.github.com/users/thethiny/followers', 'following_url': 'https://api.github.com/users/thethiny/following{/other_user}', 'gists_url': 'https://api.github.com/users/thethiny/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/thethiny/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/thethiny/subscriptions', 'organizations_url': 'https://api.github.com/users/thethiny/orgs', 'repos_url': 'https://api.github.com/users/thethiny/repos', 'events_url': 'https://api.github.com/users/thethiny/events{/privacy}', 'received_events_url': 'https://api.github.com/users/thethiny/received_events', 'type': 'User', 'user_view_type': 'public', 'site_admin': False}, 'repo': {'id': 1298654395, 'node_id': 'R_kgDOTWfkuw', 'name': 'dolphin', 'full_name': 'thethiny/dolphin', 'private': False, 'owner': {'login': 'thethiny', 'id': 6018214, 'node_id': 'MDQ6VXNlcjYwMTgyMTQ=', 'avatar_url': 'https://avatars.githubusercontent.com/u/6018214?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/thethiny', 'html_url': 'https://github.com/thethiny', 'followers_url': 'https://api.github.com/users/thethiny/followers', 'following_url': 'https://api.github.com/users/thethiny/following{/other_user}', 'gists_url': 'https://api.github.com/users/thethiny/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/thethiny/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/thethiny/subscriptions', 'organizations_url': 'https://api.github.com/users/thethiny/orgs', 'repos_url': 'https://api.github.com/users/thethiny/repos', 'events_url': 'https://api.github.com/users/thethiny/events{/privacy}', 'received_events_url': 'https://api.github.com/users/thethiny/received_events', 'type': 'User', 'user_view_type': 'public', 'site_admin': False}, 'html_url': 'https://github.com/thethiny/dolphin', 'description': 'Dolphin is a GameCube / Wii emulator, allowing you to play games for these two platforms on PC with improvements.', 'fork': True, 'url': 'https://api.github.com/repos/thethiny/dolphin', 'forks_url': 'https://api.github.com/repos/thethiny/dolphin/forks', 'keys_url': 'https://api.github.com/repos/thethiny/dolphin/keys{/key_id}', 'collaborators_url': 'https://api.github.com/repos/thethiny/dolphin/collaborators{/collaborator}', 'teams_url': 'https://api.github.com/repos/thethiny/dolphin/teams', 'hooks_url': 'https://api.github.com/repos/thethiny/dolphin/hooks', 'issue_events_url': 'https://api.github.com/repos/thethiny/dolphin/issues/events{/number}', 'events_url': 'https://api.github.com/repos/thethiny/dolphin/events', 'assignees_url': 'https://api.github.com/repos/thethiny/dolphin/assignees{/user}', 'branches_url': 'https://api.github.com/repos/thethiny/dolphin/branches{/branch}', 'tags_url': 'https://api.github.com/repos/thethiny/dolphin/tags', 'blobs_url': 'https://api.github.com/repos/thethiny/dolphin/git/blobs{/sha}', 'git_tags_url': 'https://api.github.com/repos/thethiny/dolphin/git/tags{/sha}', 'git_refs_url': 'https://api.github.com/repos/thethiny/dolphin/git/refs{/sha}', 'trees_url': 'https://api.github.com/repos/thethiny/dolphin/git/trees{/sha}', 'statuses_url': 'https://api.github.com/repos/thethiny/dolphin/statuses/{sha}', 'languages_url': 'https://api.github.com/repos/thethiny/dolphin/languages', 'stargazers_url': 'https://api.github.com/repos/thethiny/dolphin/stargazers', 'contributors_url': 'https://api.github.com/repos/thethiny/dolphin/contributors', 'subscribers_url': 'https://api.github.com/repos/thethiny/dolphin/subscribers', 'subscription_url': 'https://api.github.com/repos/thethiny/dolphin/subscription', 'commits_url': 'https://api.github.com/repos/thethiny/dolphin/commits{/sha}', 'git_commits_url': 'https://api.github.com/repos/thethiny/dolphin/git/commits{/sha}', 'comments_url': 'https://api.github.com/repos/thethiny/dolphin/comments{/number}', 'issue_comment_url': 'https://api.github.com/repos/thethiny/dolphin/issues/comments{/number}', 'contents_url': 'https://api.github.com/repos/thethiny/dolphin/contents/{+path}', 'compare_url': 'https://api.github.com/repos/thethiny/dolphin/compare/{base}...{head}', 'merges_url': 'https://api.github.com/repos/thethiny/dolphin/merges', 'archive_url': 'https://api.github.com/repos/thethiny/dolphin/{archive_format}{/ref}', 'downloads_url': 'https://api.github.com/repos/thethiny/dolphin/downloads', 'issues_url': 'https://api.github.com/repos/thethiny/dolphin/issues{/number}', 'pulls_url': 'https://api.github.com/repos/thethiny/dolphin/pulls{/number}', 'milestones_url': 'https://api.github.com/repos/thethiny/dolphin/milestones{/number}', 'notifications_url': 'https://api.github.com/repos/thethiny/dolphin/notifications{?since,all,participating}', 'labels_url': 'https://api.github.com/repos/thethiny/dolphin/labels{/name}', 'releases_url': 'https://api.github.com/repos/thethiny/dolphin/releases{/id}', 'deployments_url': 'https://api.github.com/repos/thethiny/dolphin/deployments', 'created_at': '2026-07-12T22:09:13Z', 'updated_at': '2026-07-12T22:09:13Z', 'pushed_at': '2026-07-18T20:35:03Z', 'git_url': 'git://github.com/thethiny/dolphin.git', 'ssh_url': 'git@github.com:thethiny/dolphin.git', 'clone_url': 'https://github.com/thethiny/dolphin.git', 'svn_url': 'https://github.com/thethiny/dolphin', 'homepage': 'https://dolphin-emu.org', 'size': 515471, 'stargazers_count': 0, 'watchers_count': 0, 'language': None, 'has_issues': False, 'has_projects': True, 'has_downloads': True, 'has_wiki': True, 'has_pages': False, 'has_discussions': False, 'forks_count': 0, 'mirror_url': None, 'archived': False, 'disabled': False, 'open_issues_count': 0, 'license': {'key': 'other', 'name': 'Other', 'spdx_id': 'NOASSERTION', 'url': None, 'node_id': 'MDc6TGljZW5zZTA='}, 'allow_forking': True, 'is_template': False, 'web_commit_signoff_required': False, 'has_pull_requests': True, 'pull_request_creation_policy': 'all', 'topics': [], 'visibility': 'public', 'forks': 0, 'open_issues': 0, 'watchers': 0, 'default_branch': 'master', 'allow_squash_merge': True, 'allow_merge_commit': True, 'allow_rebase_merge': True, 'allow_auto_merge': False, 'delete_branch_on_merge': False, 'allow_update_branch': False, 'use_squash_pr_title_as_default': False, 'squash_merge_commit_message': 'COMMIT_MESSAGES', 'squash_merge_commit_title': 'COMMIT_OR_PR_TITLE', 'merge_commit_message': 'PR_TITLE', 'merge_commit_title': 'MERGE_MESSAGE'}}, 'base': {'label': 'dolphin-emu:master', 'ref': 'master', 'sha': 'd3b2943807dd0073f7767947466dd73cccfef319', 'user': {'login': 'dolphin-emu', 'id': 5050316, 'node_id': 'MDEyOk9yZ2FuaXphdGlvbjUwNTAzMTY=', 'avatar_url': 'https://avatars.githubusercontent.com/u/5050316?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/dolphin-emu', 'html_url': 'https://github.com/dolphin-emu', 'followers_url': 'https://api.github.com/users/dolphin-emu/followers', 'following_url': 'https://api.github.com/users/dolphin-emu/following{/other_user}', 'gists_url': 'https://api.github.com/users/dolphin-emu/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/dolphin-emu/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/dolphin-emu/subscriptions', 'organizations_url': 'https://api.github.com/users/dolphin-emu/orgs', 'repos_url': 'https://api.github.com/users/dolphin-emu/repos', 'events_url': 'https://api.github.com/users/dolphin-emu/events{/privacy}', 'received_events_url': 'https://api.github.com/users/dolphin-emu/received_events', 'type': 'Organization', 'user_view_type': 'public', 'site_admin': False}, 'repo': {'id': 11577304, 'node_id': 'MDEwOlJlcG9zaXRvcnkxMTU3NzMwNA==', 'name': 'dolphin', 'full_name': 'dolphin-emu/dolphin', 'private': False, 'owner': {'login': 'dolphin-emu', 'id': 5050316, 'node_id': 'MDEyOk9yZ2FuaXphdGlvbjUwNTAzMTY=', 'avatar_url': 'https://avatars.githubusercontent.com/u/5050316?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/dolphin-emu', 'html_url': 'https://github.com/dolphin-emu', 'followers_url': 'https://api.github.com/users/dolphin-emu/followers', 'following_url': 'https://api.github.com/users/dolphin-emu/following{/other_user}', 'gists_url': 'https://api.github.com/users/dolphin-emu/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/dolphin-emu/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/dolphin-emu/subscriptions', 'organizations_url': 'https://api.github.com/users/dolphin-emu/orgs', 'repos_url': 'https://api.github.com/users/dolphin-emu/repos', 'events_url': 'https://api.github.com/users/dolphin-emu/events{/privacy}', 'received_events_url': 'https://api.github.com/users/dolphin-emu/received_events', 'type': 'Organization', 'user_view_type': 'public', 'site_admin': False}, 'html_url': 'https://github.com/dolphin-emu/dolphin', 'description': 'Dolphin is a GameCube / Wii emulator, allowing you to play games for these two platforms on PC with improvements.', 'fork': False, 'url': 'https://api.github.com/repos/dolphin-emu/dolphin', 'forks_url': 'https://api.github.com/repos/dolphin-emu/dolphin/forks', 'keys_url': 'https://api.github.com/repos/dolphin-emu/dolphin/keys{/key_id}', 'collaborators_url': 'https://api.github.com/repos/dolphin-emu/dolphin/collaborators{/collaborator}', 'teams_url': 'https://api.github.com/repos/dolphin-emu/dolphin/teams', 'hooks_url': 'https://api.github.com/repos/dolphin-emu/dolphin/hooks', 'issue_events_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/events{/number}', 'events_url': 'https://api.github.com/repos/dolphin-emu/dolphin/events', 'assignees_url': 'https://api.github.com/repos/dolphin-emu/dolphin/assignees{/user}', 'branches_url': 'https://api.github.com/repos/dolphin-emu/dolphin/branches{/branch}', 'tags_url': 'https://api.github.com/repos/dolphin-emu/dolphin/tags', 'blobs_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/blobs{/sha}', 'git_tags_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/tags{/sha}', 'git_refs_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/refs{/sha}', 'trees_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/trees{/sha}', 'statuses_url': 'https://api.github.com/repos/dolphin-emu/dolphin/statuses/{sha}', 'languages_url': 'https://api.github.com/repos/dolphin-emu/dolphin/languages', 'stargazers_url': 'https://api.github.com/repos/dolphin-emu/dolphin/stargazers', 'contributors_url': 'https://api.github.com/repos/dolphin-emu/dolphin/contributors', 'subscribers_url': 'https://api.github.com/repos/dolphin-emu/dolphin/subscribers', 'subscription_url': 'https://api.github.com/repos/dolphin-emu/dolphin/subscription', 'commits_url': 'https://api.github.com/repos/dolphin-emu/dolphin/commits{/sha}', 'git_commits_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/commits{/sha}', 'comments_url': 'https://api.github.com/repos/dolphin-emu/dolphin/comments{/number}', 'issue_comment_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/comments{/number}', 'contents_url': 'https://api.github.com/repos/dolphin-emu/dolphin/contents/{+path}', 'compare_url': 'https://api.github.com/repos/dolphin-emu/dolphin/compare/{base}...{head}', 'merges_url': 'https://api.github.com/repos/dolphin-emu/dolphin/merges', 'archive_url': 'https://api.github.com/repos/dolphin-emu/dolphin/{archive_format}{/ref}', 'downloads_url': 'https://api.github.com/repos/dolphin-emu/dolphin/downloads', 'issues_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues{/number}', 'pulls_url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls{/number}', 'milestones_url': 'https://api.github.com/repos/dolphin-emu/dolphin/milestones{/number}', 'notifications_url': 'https://api.github.com/repos/dolphin-emu/dolphin/notifications{?since,all,participating}', 'labels_url': 'https://api.github.com/repos/dolphin-emu/dolphin/labels{/name}', 'releases_url': 'https://api.github.com/repos/dolphin-emu/dolphin/releases{/id}', 'deployments_url': 'https://api.github.com/repos/dolphin-emu/dolphin/deployments', 'created_at': '2013-07-22T09:07:57Z', 'updated_at': '2026-07-18T18:44:16Z', 'pushed_at': '2026-07-18T10:34:54Z', 'git_url': 'git://github.com/dolphin-emu/dolphin.git', 'ssh_url': 'git@github.com:dolphin-emu/dolphin.git', 'clone_url': 'https://github.com/dolphin-emu/dolphin.git', 'svn_url': 'https://github.com/dolphin-emu/dolphin', 'homepage': 'https://dolphin-emu.org', 'size': 558448, 'stargazers_count': 15272, 'watchers_count': 15272, 'language': 'C++', 'has_issues': False, 'has_projects': False, 'has_downloads': True, 'has_wiki': True, 'has_pages': False, 'has_discussions': False, 'forks_count': 3162, 'mirror_url': None, 'archived': False, 'disabled': False, 'open_issues_count': 446, 'license': {'key': 'other', 'name': 'Other', 'spdx_id': 'NOASSERTION', 'url': None, 'node_id': 'MDc6TGljZW5zZTA='}, 'allow_forking': True, 'is_template': False, 'web_commit_signoff_required': False, 'has_pull_requests': True, 'pull_request_creation_policy': 'all', 'topics': ['cpp', 'emulation', 'emulator', 'gamecube', 'wii'], 'visibility': 'public', 'forks': 3162, 'open_issues': 446, 'watchers': 15272, 'default_branch': 'master', 'allow_squash_merge': False, 'allow_merge_commit': True, 'allow_rebase_merge': False, 'allow_auto_merge': False, 'delete_branch_on_merge': False, 'allow_update_branch': False, 'use_squash_pr_title_as_default': False, 'squash_merge_commit_message': 'COMMIT_MESSAGES', 'squash_merge_commit_title': 'COMMIT_OR_PR_TITLE', 'merge_commit_message': 'PR_TITLE', 'merge_commit_title': 'MERGE_MESSAGE'}}, '_links': {'self': {'href': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/14731'}, 'html': {'href': 'https://github.com/dolphin-emu/dolphin/pull/14731'}, 'issue': {'href': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/14731'}, 'comments': {'href': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/14731/comments'}, 'review_comments': {'href': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/14731/comments'}, 'review_comment': {'href': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/comments{/number}'}, 'commits': {'href': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/14731/commits'}, 'statuses': {'href': 'https://api.github.com/repos/dolphin-emu/dolphin/statuses/24b41d58df2315831b74f76b95417f2739d02f9d'}}, 'author_association': 'NONE', 'auto_merge': None, 'assignee': None, 'active_lock_reason': None}, 'repository': {'id': 11577304, 'node_id': 'MDEwOlJlcG9zaXRvcnkxMTU3NzMwNA==', 'name': 'dolphin', 'full_name': 'dolphin-emu/dolphin', 'private': False, 'owner': {'login': 'dolphin-emu', 'id': 5050316, 'node_id': 'MDEyOk9yZ2FuaXphdGlvbjUwNTAzMTY=', 'avatar_url': 'https://avatars.githubusercontent.com/u/5050316?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/dolphin-emu', 'html_url': 'https://github.com/dolphin-emu', 'followers_url': 'https://api.github.com/users/dolphin-emu/followers', 'following_url': 'https://api.github.com/users/dolphin-emu/following{/other_user}', 'gists_url': 'https://api.github.com/users/dolphin-emu/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/dolphin-emu/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/dolphin-emu/subscriptions', 'organizations_url': 'https://api.github.com/users/dolphin-emu/orgs', 'repos_url': 'https://api.github.com/users/dolphin-emu/repos', 'events_url': 'https://api.github.com/users/dolphin-emu/events{/privacy}', 'received_events_url': 'https://api.github.com/users/dolphin-emu/received_events', 'type': 'Organization', 'user_view_type': 'public', 'site_admin': False}, 'html_url': 'https://github.com/dolphin-emu/dolphin', 'description': 'Dolphin is a GameCube / Wii emulator, allowing you to play games for these two platforms on PC with improvements.', 'fork': False, 'url': 'https://api.github.com/repos/dolphin-emu/dolphin', 'forks_url': 'https://api.github.com/repos/dolphin-emu/dolphin/forks', 'keys_url': 'https://api.github.com/repos/dolphin-emu/dolphin/keys{/key_id}', 'collaborators_url': 'https://api.github.com/repos/dolphin-emu/dolphin/collaborators{/collaborator}', 'teams_url': 'https://api.github.com/repos/dolphin-emu/dolphin/teams', 'hooks_url': 'https://api.github.com/repos/dolphin-emu/dolphin/hooks', 'issue_events_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/events{/number}', 'events_url': 'https://api.github.com/repos/dolphin-emu/dolphin/events', 'assignees_url': 'https://api.github.com/repos/dolphin-emu/dolphin/assignees{/user}', 'branches_url': 'https://api.github.com/repos/dolphin-emu/dolphin/branches{/branch}', 'tags_url': 'https://api.github.com/repos/dolphin-emu/dolphin/tags', 'blobs_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/blobs{/sha}', 'git_tags_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/tags{/sha}', 'git_refs_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/refs{/sha}', 'trees_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/trees{/sha}', 'statuses_url': 'https://api.github.com/repos/dolphin-emu/dolphin/statuses/{sha}', 'languages_url': 'https://api.github.com/repos/dolphin-emu/dolphin/languages', 'stargazers_url': 'https://api.github.com/repos/dolphin-emu/dolphin/stargazers', 'contributors_url': 'https://api.github.com/repos/dolphin-emu/dolphin/contributors', 'subscribers_url': 'https://api.github.com/repos/dolphin-emu/dolphin/subscribers', 'subscription_url': 'https://api.github.com/repos/dolphin-emu/dolphin/subscription', 'commits_url': 'https://api.github.com/repos/dolphin-emu/dolphin/commits{/sha}', 'git_commits_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/commits{/sha}', 'comments_url': 'https://api.github.com/repos/dolphin-emu/dolphin/comments{/number}', 'issue_comment_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/comments{/number}', 'contents_url': 'https://api.github.com/repos/dolphin-emu/dolphin/contents/{+path}', 'compare_url': 'https://api.github.com/repos/dolphin-emu/dolphin/compare/{base}...{head}', 'merges_url': 'https://api.github.com/repos/dolphin-emu/dolphin/merges', 'archive_url': 'https://api.github.com/repos/dolphin-emu/dolphin/{archive_format}{/ref}', 'downloads_url': 'https://api.github.com/repos/dolphin-emu/dolphin/downloads', 'issues_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues{/number}', 'pulls_url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls{/number}', 'milestones_url': 'https://api.github.com/repos/dolphin-emu/dolphin/milestones{/number}', 'notifications_url': 'https://api.github.com/repos/dolphin-emu/dolphin/notifications{?since,all,participating}', 'labels_url': 'https://api.github.com/repos/dolphin-emu/dolphin/labels{/name}', 'releases_url': 'https://api.github.com/repos/dolphin-emu/dolphin/releases{/id}', 'deployments_url': 'https://api.github.com/repos/dolphin-emu/dolphin/deployments', 'created_at': '2013-07-22T09:07:57Z', 'updated_at': '2026-07-18T18:44:16Z', 'pushed_at': '2026-07-18T10:34:54Z', 'git_url': 'git://github.com/dolphin-emu/dolphin.git', 'ssh_url': 'git@github.com:dolphin-emu/dolphin.git', 'clone_url': 'https://github.com/dolphin-emu/dolphin.git', 'svn_url': 'https://github.com/dolphin-emu/dolphin', 'homepage': 'https://dolphin-emu.org', 'size': 558448, 'stargazers_count': 15272, 'watchers_count': 15272, 'language': 'C++', 'has_issues': False, 'has_projects': False, 'has_downloads': True, 'has_wiki': True, 'has_pages': False, 'has_discussions': False, 'forks_count': 3162, 'mirror_url': None, 'archived': False, 'disabled': False, 'open_issues_count': 446, 'license': {'key': 'other', 'name': 'Other', 'spdx_id': 'NOASSERTION', 'url': None, 'node_id': 'MDc6TGljZW5zZTA='}, 'allow_forking': True, 'is_template': False, 'web_commit_signoff_required': False, 'has_pull_requests': True, 'pull_request_creation_policy': 'all', 'topics': ['cpp', 'emulation', 'emulator', 'gamecube', 'wii'], 'visibility': 'public', 'forks': 3162, 'open_issues': 446, 'watchers': 15272, 'default_branch': 'master', 'custom_properties': {}}, 'organization': {'login': 'dolphin-emu', 'id': 5050316, 'node_id': 'MDEyOk9yZ2FuaXphdGlvbjUwNTAzMTY=', 'url': 'https://api.github.com/orgs/dolphin-emu', 'repos_url': 'https://api.github.com/orgs/dolphin-emu/repos', 'events_url': 'https://api.github.com/orgs/dolphin-emu/events', 'hooks_url': 'https://api.github.com/orgs/dolphin-emu/hooks', 'issues_url': 'https://api.github.com/orgs/dolphin-emu/issues', 'members_url': 'https://api.github.com/orgs/dolphin-emu/members{/member}', 'public_members_url': 'https://api.github.com/orgs/dolphin-emu/public_members{/member}', 'avatar_url': 'https://avatars.githubusercontent.com/u/5050316?v=4', 'description': ''}, 'sender': {'login': 'phire', 'id': 138484, 'node_id': 'MDQ6VXNlcjEzODQ4NA==', 'avatar_url': 'https://avatars.githubusercontent.com/u/138484?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/phire', 'html_url': 'https://github.com/phire', 'followers_url': 'https://api.github.com/users/phire/followers', 'following_url': 'https://api.github.com/users/phire/following{/other_user}', 'gists_url': 'https://api.github.com/users/phire/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/phire/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/phire/subscriptions', 'organizations_url': 'https://api.github.com/users/phire/orgs', 'repos_url': 'https://api.github.com/users/phire/repos', 'events_url': 'https://api.github.com/users/phire/events{/privacy}', 'received_events_url': 'https://api.github.com/users/phire/received_events', 'type': 'User', 'user_view_type': 'public', 'site_admin': False}, 'installation': {'id': 35437981, 'node_id': 'MDIzOkludGVncmF0aW9uSW5zdGFsbGF0aW9uMzU0Mzc5ODE='}}, 'type': 'raw_gh_hook'}
2026-07-18T22:26:25.644262	{'source': 'webserver', 'gh_type': 'pull_request_review_comment', 'raw': {'action': 'created', 'comment': {'url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/comments/3609277919', 'pull_request_review_id': 4729322283, 'id': 3609277919, 'node_id': 'PRRC_kwDOALCn2M7XITXf', 'diff_hunk': '@@ -119,22 +144,191 @@ bool WbfsFileReader::ReadHeader()\n   return m_header.disc_table[0] != 0;\n }\n \n+bool WbfsFileReader::ReadNKitHeader()\n+{\n+  const u64 gap_type_blocks = (DL_DVD_SIZE + m_wbfs_sector_size - 1) / m_wbfs_sector_size;\n+  m_nkit_info = NKit::ReadHeaderFromFile(m_files[0].file, NKit::HEADER_OFFSET, gap_type_blocks);\n+  if (!m_nkit_info.valid)\n+    return false;\n+\n+  m_has_nkit_header = true;\n+  return true;\n+}\n+\n+bool WbfsFileReader::IsBlockStored(u64 block_index) const\n+{\n+  return block_index < m_blocks_per_disc && m_wlba_table[block_index] != 0;\n+}\n+\n+bool WbfsFileReader::IsGapJunk(u64 block_index) const\n+{\n+  return NKit::IsGapJunk(m_nkit_info.gap_type, block_index);\n+}\n+\n+void WbfsFileReader::GenerateJunkData(u64 disc_offset, u64 size, u8* out) const\n+{\n+  LaggedFibonacciGenerator::FillJunkData(out, static_cast<size_t>(size), disc_offset, m_disc_id,\n+                                         m_disc_num);\n+}\n+\n+void WbfsFileReader::ReadPartitionInfo()\n+{\n+  std::unique_ptr<VolumeDisc> volume = CreateDisc(CopyReader());\n+  if (!volume)\n+    return;\n+\n+  for (const Partition& partition : volume->GetPartitions())\n+  {\n+    const auto& ticket = volume->GetTicket(partition);\n+    const std::array<u8, 16> title_key = ticket.GetTitleKey();\n+\n+    u8 data_info[8];\n+    if (!Read(partition.offset + 0x2B8, 8, data_info))\n+      continue;\n+\n+    PartitionEntry entry;\n+    entry.data_offset = partition.offset + (static_cast<u64>(Common::swap32(data_info)) << 2);\n+    entry.data_size = static_cast<u64>(Common::swap32(data_info + 4)) << 2;\n+    entry.key = title_key;\n+    m_partitions.push_back(entry);\n+  }\n+}\n+\n+const WbfsFileReader::PartitionEntry* WbfsFileReader::FindPartition(u64 disc_offset) const\n+{\n+  for (const auto& p : m_partitions)\n+  {\n+    if (disc_offset >= p.data_offset && disc_offset < p.data_offset + p.data_size)\n+      return &p;\n+  }\n+  return nullptr;\n+}\n+\n+const WbfsFileReader::PartitionEntry*\n+WbfsFileReader::FindPartitionByDataOffset(u64 partition_data_offset) const\n+{\n+  for (const auto& p : m_partitions)\n+  {\n+    if (p.data_offset == partition_data_offset)\n+      return &p;\n+  }\n+  return nullptr;\n+}\n+\n+bool WbfsFileReader::SupportsReadWiiDecrypted(u64 offset, u64 size, u64 partition_data_offset) const\n+{\n+  if (!m_has_nkit_header)\n+    return false;\n+\n+  const u64 block_in_partition = offset / VolumeWii::BLOCK_DATA_SIZE;\n+  const u64 disc_offset = partition_data_offset + block_in_partition * VolumeWii::BLOCK_TOTAL_SIZE;\n+  const u64 wbfs_block = disc_offset >> m_header.wbfs_sector_shift;\n+\n+  return wbfs_block < m_blocks_per_disc && !IsBlockStored(wbfs_block);\n+}\n+\n+bool WbfsFileReader::ReadWiiDecrypted(u64 offset, u64 size, u8* out_ptr, u64 partition_data_offset)\n+{\n+  const PartitionEntry* pe = FindPartitionByDataOffset(partition_data_offset);\n+  if (!pe)\n+    return false;\n+\n+  auto aes_ctx = Common::AES::CreateContextDecrypt(pe->key.data());\n+  std::vector<u8> encrypted(VolumeWii::BLOCK_TOTAL_SIZE);\n+  std::vector<u8> decrypted(VolumeWii::BLOCK_DATA_SIZE);\n+\n+  while (size > 0)\n+  {\n+    const u64 block_in_partition = offset / VolumeWii::BLOCK_DATA_SIZE;\n+    const u64 offset_in_block = offset % VolumeWii::BLOCK_DATA_SIZE;\n+    const u64 bytes_in_block = VolumeWii::BLOCK_DATA_SIZE - offset_in_block;\n+    const size_t read_size = static_cast<size_t>(std::min(bytes_in_block, size));\n+\n+    const u64 disc_offset =\n+        partition_data_offset + block_in_partition * VolumeWii::BLOCK_TOTAL_SIZE;\n+    const u64 wbfs_block = disc_offset >> m_header.wbfs_sector_shift;\n+\n+    if (IsBlockStored(wbfs_block))\n+    {\n+      u64 available;\n+      auto& file = SeekToCluster(disc_offset, &available);\n+      if (available < VolumeWii::BLOCK_TOTAL_SIZE ||\n+          !file.Read(encrypted.data(), VolumeWii::BLOCK_TOTAL_SIZE))\n+        return false;\n+      VolumeWii::DecryptBlockData(encrypted.data(), decrypted.data(), aes_ctx.get());\n+      std::memcpy(out_ptr, decrypted.data() + offset_in_block, read_size);\n+    }', 'path': 'Source/Core/DiscIO/WbfsBlob.cpp', 'commit_id': '24b41d58df2315831b74f76b95417f2739d02f9d', 'original_commit_id': '24b41d58df2315831b74f76b95417f2739d02f9d', 'user': {'login': 'phire', 'id': 138484, 'node_id': 'MDQ6VXNlcjEzODQ4NA==', 'avatar_url': 'https://avatars.githubusercontent.com/u/138484?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/phire', 'html_url': 'https://github.com/phire', 'followers_url': 'https://api.github.com/users/phire/followers', 'following_url': 'https://api.github.com/users/phire/following{/other_user}', 'gists_url': 'https://api.github.com/users/phire/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/phire/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/phire/subscriptions', 'organizations_url': 'https://api.github.com/users/phire/orgs', 'repos_url': 'https://api.github.com/users/phire/repos', 'events_url': 'https://api.github.com/users/phire/events{/privacy}', 'received_events_url': 'https://api.github.com/users/phire/received_events', 'type': 'User', 'user_view_type': 'public', 'site_admin': False}, 'body': "> ReadWiiDecrypted still contains manual AES decryption for stored blocks because VolumeWii::EncryptGroup calls it directly without checking SupportsReadWiiDecrypted\n\nBut you are calling `EncryptGroup` for blocks that don't have data, right? I don't see why this would be reachable.", 'created_at': '2026-07-18T22:05:05Z', 'updated_at': '2026-07-18T22:26:23Z', 'html_url': 'https://github.com/dolphin-emu/dolphin/pull/14731#discussion_r3609277919', 'pull_request_url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/14731', '_links': {'self': {'href': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/comments/3609277919'}, 'html': {'href': 'https://github.com/dolphin-emu/dolphin/pull/14731#discussion_r3609277919'}, 'pull_request': {'href': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/14731'}}, 'reactions': {'url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/comments/3609277919/reactions', 'total_count': 0, '+1': 0, '-1': 0, 'laugh': 0, 'hooray': 0, 'confused': 0, 'heart': 0, 'rocket': 0, 'eyes': 0}, 'start_line': 251, 'original_start_line': 251, 'start_side': 'RIGHT', 'line': 260, 'original_line': 260, 'side': 'RIGHT', 'author_association': 'MEMBER', 'original_position': 204, 'position': 204, 'subject_type': 'line'}, 'pull_request': {'url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/14731', 'id': 4056977334, 'node_id': 'PR_kwDOALCn2M7x0I-2', 'html_url': 'https://github.com/dolphin-emu/dolphin/pull/14731', 'diff_url': 'https://github.com/dolphin-emu/dolphin/pull/14731.diff', 'patch_url': 'https://github.com/dolphin-emu/dolphin/pull/14731.patch', 'issue_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/14731', 'number': 14731, 'state': 'open', 'locked': False, 'title': 'Convert To WBFS Support', 'user': {'login': 'thethiny', 'id': 6018214, 'node_id': 'MDQ6VXNlcjYwMTgyMTQ=', 'avatar_url': 'https://avatars.githubusercontent.com/u/6018214?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/thethiny', 'html_url': 'https://github.com/thethiny', 'followers_url': 'https://api.github.com/users/thethiny/followers', 'following_url': 'https://api.github.com/users/thethiny/following{/other_user}', 'gists_url': 'https://api.github.com/users/thethiny/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/thethiny/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/thethiny/subscriptions', 'organizations_url': 'https://api.github.com/users/thethiny/orgs', 'repos_url': 'https://api.github.com/users/thethiny/repos', 'events_url': 'https://api.github.com/users/thethiny/events{/privacy}', 'received_events_url': 'https://api.github.com/users/thethiny/received_events', 'type': 'User', 'user_view_type': 'public', 'site_admin': False}, 'body': "This PR introduces Conversion **to** WBFS support. WBFS is the format that is used by USB Loaders on a real Wii device.\r\n\r\n## Design decisions & hardcoded values\r\nThe writer uses fixed sector sizes that match what [libwbfs (the reference implementation by kwiirk)](https://github.com/kwiirk/wbfs/blob/master/libwbfs/libwbfs.c#L128-L134) computes for a standard single-layer Wii disc. These 2 hardcodes are stable and work correctly across all my testings.\r\n- HD sector shift: 9 (512 bytes)\r\n- WBFS sector shift: 21 (2 MiB)\r\nThese are not configurable via the UI. All existing WBFS tools use these values, and since the aim is to support USB Loaders then this has been tested and it is working on a real Wii.\r\n\r\nConverting from WBFS is not enabled. The existing `WbfsFileReader` reports `DataSizeType::UpperBound`, and `ShouldAllowConversion()` requires `Accurate`. I am able to support this but since it was hardcoded by the Dolphin team I thought a discussion is warranted.\r\n\r\n## Testing\r\n- Verified with DolphinTool header and DolphinTool verify\r\n- Verified with wit FILETYPE and wit DUMP (Wiimm's ISO Tools recognizes valid WBFS structure, partitions, encryption)\r\n- Tested ISO to WBFS and RVZ to WBFS conversions\r\n- Output file sizes match Wii Backup Manager when scrubbing is enabled (~0.1% difference), works when scrubbing is disabled.\r\n- Output WBFS files play correctly in Dolphin\r\n- Output WBFS files play correctly on a real Wii using USB Loader GX e25c4f3\r\n", 'created_at': '2026-07-15T01:16:25Z', 'updated_at': '2026-07-18T22:16:59Z', 'closed_at': None, 'merged_at': None, 'merge_commit_sha': '228f93416dd80eb09da834ad7852c8eaa4d9212b', 'assignees': [], 'requested_reviewers': [], 'requested_teams': [], 'labels': [], 'milestone': None, 'draft': False, 'commits_url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/14731/commits', 'review_comments_url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/14731/comments', 'review_comment_url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/comments{/number}', 'comments_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/14731/comments', 'statuses_url': 'https://api.github.com/repos/dolphin-emu/dolphin/statuses/24b41d58df2315831b74f76b95417f2739d02f9d', 'head': {'label': 'thethiny:wbfs-conversion', 'ref': 'wbfs-conversion', 'sha': '24b41d58df2315831b74f76b95417f2739d02f9d', 'user': {'login': 'thethiny', 'id': 6018214, 'node_id': 'MDQ6VXNlcjYwMTgyMTQ=', 'avatar_url': 'https://avatars.githubusercontent.com/u/6018214?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/thethiny', 'html_url': 'https://github.com/thethiny', 'followers_url': 'https://api.github.com/users/thethiny/followers', 'following_url': 'https://api.github.com/users/thethiny/following{/other_user}', 'gists_url': 'https://api.github.com/users/thethiny/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/thethiny/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/thethiny/subscriptions', 'organizations_url': 'https://api.github.com/users/thethiny/orgs', 'repos_url': 'https://api.github.com/users/thethiny/repos', 'events_url': 'https://api.github.com/users/thethiny/events{/privacy}', 'received_events_url': 'https://api.github.com/users/thethiny/received_events', 'type': 'User', 'user_view_type': 'public', 'site_admin': False}, 'repo': {'id': 1298654395, 'node_id': 'R_kgDOTWfkuw', 'name': 'dolphin', 'full_name': 'thethiny/dolphin', 'private': False, 'owner': {'login': 'thethiny', 'id': 6018214, 'node_id': 'MDQ6VXNlcjYwMTgyMTQ=', 'avatar_url': 'https://avatars.githubusercontent.com/u/6018214?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/thethiny', 'html_url': 'https://github.com/thethiny', 'followers_url': 'https://api.github.com/users/thethiny/followers', 'following_url': 'https://api.github.com/users/thethiny/following{/other_user}', 'gists_url': 'https://api.github.com/users/thethiny/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/thethiny/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/thethiny/subscriptions', 'organizations_url': 'https://api.github.com/users/thethiny/orgs', 'repos_url': 'https://api.github.com/users/thethiny/repos', 'events_url': 'https://api.github.com/users/thethiny/events{/privacy}', 'received_events_url': 'https://api.github.com/users/thethiny/received_events', 'type': 'User', 'user_view_type': 'public', 'site_admin': False}, 'html_url': 'https://github.com/thethiny/dolphin', 'description': 'Dolphin is a GameCube / Wii emulator, allowing you to play games for these two platforms on PC with improvements.', 'fork': True, 'url': 'https://api.github.com/repos/thethiny/dolphin', 'forks_url': 'https://api.github.com/repos/thethiny/dolphin/forks', 'keys_url': 'https://api.github.com/repos/thethiny/dolphin/keys{/key_id}', 'collaborators_url': 'https://api.github.com/repos/thethiny/dolphin/collaborators{/collaborator}', 'teams_url': 'https://api.github.com/repos/thethiny/dolphin/teams', 'hooks_url': 'https://api.github.com/repos/thethiny/dolphin/hooks', 'issue_events_url': 'https://api.github.com/repos/thethiny/dolphin/issues/events{/number}', 'events_url': 'https://api.github.com/repos/thethiny/dolphin/events', 'assignees_url': 'https://api.github.com/repos/thethiny/dolphin/assignees{/user}', 'branches_url': 'https://api.github.com/repos/thethiny/dolphin/branches{/branch}', 'tags_url': 'https://api.github.com/repos/thethiny/dolphin/tags', 'blobs_url': 'https://api.github.com/repos/thethiny/dolphin/git/blobs{/sha}', 'git_tags_url': 'https://api.github.com/repos/thethiny/dolphin/git/tags{/sha}', 'git_refs_url': 'https://api.github.com/repos/thethiny/dolphin/git/refs{/sha}', 'trees_url': 'https://api.github.com/repos/thethiny/dolphin/git/trees{/sha}', 'statuses_url': 'https://api.github.com/repos/thethiny/dolphin/statuses/{sha}', 'languages_url': 'https://api.github.com/repos/thethiny/dolphin/languages', 'stargazers_url': 'https://api.github.com/repos/thethiny/dolphin/stargazers', 'contributors_url': 'https://api.github.com/repos/thethiny/dolphin/contributors', 'subscribers_url': 'https://api.github.com/repos/thethiny/dolphin/subscribers', 'subscription_url': 'https://api.github.com/repos/thethiny/dolphin/subscription', 'commits_url': 'https://api.github.com/repos/thethiny/dolphin/commits{/sha}', 'git_commits_url': 'https://api.github.com/repos/thethiny/dolphin/git/commits{/sha}', 'comments_url': 'https://api.github.com/repos/thethiny/dolphin/comments{/number}', 'issue_comment_url': 'https://api.github.com/repos/thethiny/dolphin/issues/comments{/number}', 'contents_url': 'https://api.github.com/repos/thethiny/dolphin/contents/{+path}', 'compare_url': 'https://api.github.com/repos/thethiny/dolphin/compare/{base}...{head}', 'merges_url': 'https://api.github.com/repos/thethiny/dolphin/merges', 'archive_url': 'https://api.github.com/repos/thethiny/dolphin/{archive_format}{/ref}', 'downloads_url': 'https://api.github.com/repos/thethiny/dolphin/downloads', 'issues_url': 'https://api.github.com/repos/thethiny/dolphin/issues{/number}', 'pulls_url': 'https://api.github.com/repos/thethiny/dolphin/pulls{/number}', 'milestones_url': 'https://api.github.com/repos/thethiny/dolphin/milestones{/number}', 'notifications_url': 'https://api.github.com/repos/thethiny/dolphin/notifications{?since,all,participating}', 'labels_url': 'https://api.github.com/repos/thethiny/dolphin/labels{/name}', 'releases_url': 'https://api.github.com/repos/thethiny/dolphin/releases{/id}', 'deployments_url': 'https://api.github.com/repos/thethiny/dolphin/deployments', 'created_at': '2026-07-12T22:09:13Z', 'updated_at': '2026-07-12T22:09:13Z', 'pushed_at': '2026-07-18T20:35:03Z', 'git_url': 'git://github.com/thethiny/dolphin.git', 'ssh_url': 'git@github.com:thethiny/dolphin.git', 'clone_url': 'https://github.com/thethiny/dolphin.git', 'svn_url': 'https://github.com/thethiny/dolphin', 'homepage': 'https://dolphin-emu.org', 'size': 515471, 'stargazers_count': 0, 'watchers_count': 0, 'language': None, 'has_issues': False, 'has_projects': True, 'has_downloads': True, 'has_wiki': True, 'has_pages': False, 'has_discussions': False, 'forks_count': 0, 'mirror_url': None, 'archived': False, 'disabled': False, 'open_issues_count': 0, 'license': {'key': 'other', 'name': 'Other', 'spdx_id': 'NOASSERTION', 'url': None, 'node_id': 'MDc6TGljZW5zZTA='}, 'allow_forking': True, 'is_template': False, 'web_commit_signoff_required': False, 'has_pull_requests': True, 'pull_request_creation_policy': 'all', 'topics': [], 'visibility': 'public', 'forks': 0, 'open_issues': 0, 'watchers': 0, 'default_branch': 'master', 'allow_squash_merge': True, 'allow_merge_commit': True, 'allow_rebase_merge': True, 'allow_auto_merge': False, 'delete_branch_on_merge': False, 'allow_update_branch': False, 'use_squash_pr_title_as_default': False, 'squash_merge_commit_message': 'COMMIT_MESSAGES', 'squash_merge_commit_title': 'COMMIT_OR_PR_TITLE', 'merge_commit_message': 'PR_TITLE', 'merge_commit_title': 'MERGE_MESSAGE'}}, 'base': {'label': 'dolphin-emu:master', 'ref': 'master', 'sha': 'd3b2943807dd0073f7767947466dd73cccfef319', 'user': {'login': 'dolphin-emu', 'id': 5050316, 'node_id': 'MDEyOk9yZ2FuaXphdGlvbjUwNTAzMTY=', 'avatar_url': 'https://avatars.githubusercontent.com/u/5050316?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/dolphin-emu', 'html_url': 'https://github.com/dolphin-emu', 'followers_url': 'https://api.github.com/users/dolphin-emu/followers', 'following_url': 'https://api.github.com/users/dolphin-emu/following{/other_user}', 'gists_url': 'https://api.github.com/users/dolphin-emu/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/dolphin-emu/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/dolphin-emu/subscriptions', 'organizations_url': 'https://api.github.com/users/dolphin-emu/orgs', 'repos_url': 'https://api.github.com/users/dolphin-emu/repos', 'events_url': 'https://api.github.com/users/dolphin-emu/events{/privacy}', 'received_events_url': 'https://api.github.com/users/dolphin-emu/received_events', 'type': 'Organization', 'user_view_type': 'public', 'site_admin': False}, 'repo': {'id': 11577304, 'node_id': 'MDEwOlJlcG9zaXRvcnkxMTU3NzMwNA==', 'name': 'dolphin', 'full_name': 'dolphin-emu/dolphin', 'private': False, 'owner': {'login': 'dolphin-emu', 'id': 5050316, 'node_id': 'MDEyOk9yZ2FuaXphdGlvbjUwNTAzMTY=', 'avatar_url': 'https://avatars.githubusercontent.com/u/5050316?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/dolphin-emu', 'html_url': 'https://github.com/dolphin-emu', 'followers_url': 'https://api.github.com/users/dolphin-emu/followers', 'following_url': 'https://api.github.com/users/dolphin-emu/following{/other_user}', 'gists_url': 'https://api.github.com/users/dolphin-emu/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/dolphin-emu/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/dolphin-emu/subscriptions', 'organizations_url': 'https://api.github.com/users/dolphin-emu/orgs', 'repos_url': 'https://api.github.com/users/dolphin-emu/repos', 'events_url': 'https://api.github.com/users/dolphin-emu/events{/privacy}', 'received_events_url': 'https://api.github.com/users/dolphin-emu/received_events', 'type': 'Organization', 'user_view_type': 'public', 'site_admin': False}, 'html_url': 'https://github.com/dolphin-emu/dolphin', 'description': 'Dolphin is a GameCube / Wii emulator, allowing you to play games for these two platforms on PC with improvements.', 'fork': False, 'url': 'https://api.github.com/repos/dolphin-emu/dolphin', 'forks_url': 'https://api.github.com/repos/dolphin-emu/dolphin/forks', 'keys_url': 'https://api.github.com/repos/dolphin-emu/dolphin/keys{/key_id}', 'collaborators_url': 'https://api.github.com/repos/dolphin-emu/dolphin/collaborators{/collaborator}', 'teams_url': 'https://api.github.com/repos/dolphin-emu/dolphin/teams', 'hooks_url': 'https://api.github.com/repos/dolphin-emu/dolphin/hooks', 'issue_events_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/events{/number}', 'events_url': 'https://api.github.com/repos/dolphin-emu/dolphin/events', 'assignees_url': 'https://api.github.com/repos/dolphin-emu/dolphin/assignees{/user}', 'branches_url': 'https://api.github.com/repos/dolphin-emu/dolphin/branches{/branch}', 'tags_url': 'https://api.github.com/repos/dolphin-emu/dolphin/tags', 'blobs_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/blobs{/sha}', 'git_tags_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/tags{/sha}', 'git_refs_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/refs{/sha}', 'trees_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/trees{/sha}', 'statuses_url': 'https://api.github.com/repos/dolphin-emu/dolphin/statuses/{sha}', 'languages_url': 'https://api.github.com/repos/dolphin-emu/dolphin/languages', 'stargazers_url': 'https://api.github.com/repos/dolphin-emu/dolphin/stargazers', 'contributors_url': 'https://api.github.com/repos/dolphin-emu/dolphin/contributors', 'subscribers_url': 'https://api.github.com/repos/dolphin-emu/dolphin/subscribers', 'subscription_url': 'https://api.github.com/repos/dolphin-emu/dolphin/subscription', 'commits_url': 'https://api.github.com/repos/dolphin-emu/dolphin/commits{/sha}', 'git_commits_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/commits{/sha}', 'comments_url': 'https://api.github.com/repos/dolphin-emu/dolphin/comments{/number}', 'issue_comment_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/comments{/number}', 'contents_url': 'https://api.github.com/repos/dolphin-emu/dolphin/contents/{+path}', 'compare_url': 'https://api.github.com/repos/dolphin-emu/dolphin/compare/{base}...{head}', 'merges_url': 'https://api.github.com/repos/dolphin-emu/dolphin/merges', 'archive_url': 'https://api.github.com/repos/dolphin-emu/dolphin/{archive_format}{/ref}', 'downloads_url': 'https://api.github.com/repos/dolphin-emu/dolphin/downloads', 'issues_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues{/number}', 'pulls_url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls{/number}', 'milestones_url': 'https://api.github.com/repos/dolphin-emu/dolphin/milestones{/number}', 'notifications_url': 'https://api.github.com/repos/dolphin-emu/dolphin/notifications{?since,all,participating}', 'labels_url': 'https://api.github.com/repos/dolphin-emu/dolphin/labels{/name}', 'releases_url': 'https://api.github.com/repos/dolphin-emu/dolphin/releases{/id}', 'deployments_url': 'https://api.github.com/repos/dolphin-emu/dolphin/deployments', 'created_at': '2013-07-22T09:07:57Z', 'updated_at': '2026-07-18T18:44:16Z', 'pushed_at': '2026-07-18T10:34:54Z', 'git_url': 'git://github.com/dolphin-emu/dolphin.git', 'ssh_url': 'git@github.com:dolphin-emu/dolphin.git', 'clone_url': 'https://github.com/dolphin-emu/dolphin.git', 'svn_url': 'https://github.com/dolphin-emu/dolphin', 'homepage': 'https://dolphin-emu.org', 'size': 558448, 'stargazers_count': 15272, 'watchers_count': 15272, 'language': 'C++', 'has_issues': False, 'has_projects': False, 'has_downloads': True, 'has_wiki': True, 'has_pages': False, 'has_discussions': False, 'forks_count': 3162, 'mirror_url': None, 'archived': False, 'disabled': False, 'open_issues_count': 446, 'license': {'key': 'other', 'name': 'Other', 'spdx_id': 'NOASSERTION', 'url': None, 'node_id': 'MDc6TGljZW5zZTA='}, 'allow_forking': True, 'is_template': False, 'web_commit_signoff_required': False, 'has_pull_requests': True, 'pull_request_creation_policy': 'all', 'topics': ['cpp', 'emulation', 'emulator', 'gamecube', 'wii'], 'visibility': 'public', 'forks': 3162, 'open_issues': 446, 'watchers': 15272, 'default_branch': 'master', 'allow_squash_merge': False, 'allow_merge_commit': True, 'allow_rebase_merge': False, 'allow_auto_merge': False, 'delete_branch_on_merge': False, 'allow_update_branch': False, 'use_squash_pr_title_as_default': False, 'squash_merge_commit_message': 'COMMIT_MESSAGES', 'squash_merge_commit_title': 'COMMIT_OR_PR_TITLE', 'merge_commit_message': 'PR_TITLE', 'merge_commit_title': 'MERGE_MESSAGE'}}, '_links': {'self': {'href': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/14731'}, 'html': {'href': 'https://github.com/dolphin-emu/dolphin/pull/14731'}, 'issue': {'href': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/14731'}, 'comments': {'href': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/14731/comments'}, 'review_comments': {'href': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/14731/comments'}, 'review_comment': {'href': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/comments{/number}'}, 'commits': {'href': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/14731/commits'}, 'statuses': {'href': 'https://api.github.com/repos/dolphin-emu/dolphin/statuses/24b41d58df2315831b74f76b95417f2739d02f9d'}}, 'author_association': 'NONE', 'auto_merge': None, 'assignee': None, 'active_lock_reason': None}, 'repository': {'id': 11577304, 'node_id': 'MDEwOlJlcG9zaXRvcnkxMTU3NzMwNA==', 'name': 'dolphin', 'full_name': 'dolphin-emu/dolphin', 'private': False, 'owner': {'login': 'dolphin-emu', 'id': 5050316, 'node_id': 'MDEyOk9yZ2FuaXphdGlvbjUwNTAzMTY=', 'avatar_url': 'https://avatars.githubusercontent.com/u/5050316?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/dolphin-emu', 'html_url': 'https://github.com/dolphin-emu', 'followers_url': 'https://api.github.com/users/dolphin-emu/followers', 'following_url': 'https://api.github.com/users/dolphin-emu/following{/other_user}', 'gists_url': 'https://api.github.com/users/dolphin-emu/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/dolphin-emu/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/dolphin-emu/subscriptions', 'organizations_url': 'https://api.github.com/users/dolphin-emu/orgs', 'repos_url': 'https://api.github.com/users/dolphin-emu/repos', 'events_url': 'https://api.github.com/users/dolphin-emu/events{/privacy}', 'received_events_url': 'https://api.github.com/users/dolphin-emu/received_events', 'type': 'Organization', 'user_view_type': 'public', 'site_admin': False}, 'html_url': 'https://github.com/dolphin-emu/dolphin', 'description': 'Dolphin is a GameCube / Wii emulator, allowing you to play games for these two platforms on PC with improvements.', 'fork': False, 'url': 'https://api.github.com/repos/dolphin-emu/dolphin', 'forks_url': 'https://api.github.com/repos/dolphin-emu/dolphin/forks', 'keys_url': 'https://api.github.com/repos/dolphin-emu/dolphin/keys{/key_id}', 'collaborators_url': 'https://api.github.com/repos/dolphin-emu/dolphin/collaborators{/collaborator}', 'teams_url': 'https://api.github.com/repos/dolphin-emu/dolphin/teams', 'hooks_url': 'https://api.github.com/repos/dolphin-emu/dolphin/hooks', 'issue_events_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/events{/number}', 'events_url': 'https://api.github.com/repos/dolphin-emu/dolphin/events', 'assignees_url': 'https://api.github.com/repos/dolphin-emu/dolphin/assignees{/user}', 'branches_url': 'https://api.github.com/repos/dolphin-emu/dolphin/branches{/branch}', 'tags_url': 'https://api.github.com/repos/dolphin-emu/dolphin/tags', 'blobs_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/blobs{/sha}', 'git_tags_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/tags{/sha}', 'git_refs_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/refs{/sha}', 'trees_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/trees{/sha}', 'statuses_url': 'https://api.github.com/repos/dolphin-emu/dolphin/statuses/{sha}', 'languages_url': 'https://api.github.com/repos/dolphin-emu/dolphin/languages', 'stargazers_url': 'https://api.github.com/repos/dolphin-emu/dolphin/stargazers', 'contributors_url': 'https://api.github.com/repos/dolphin-emu/dolphin/contributors', 'subscribers_url': 'https://api.github.com/repos/dolphin-emu/dolphin/subscribers', 'subscription_url': 'https://api.github.com/repos/dolphin-emu/dolphin/subscription', 'commits_url': 'https://api.github.com/repos/dolphin-emu/dolphin/commits{/sha}', 'git_commits_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/commits{/sha}', 'comments_url': 'https://api.github.com/repos/dolphin-emu/dolphin/comments{/number}', 'issue_comment_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/comments{/number}', 'contents_url': 'https://api.github.com/repos/dolphin-emu/dolphin/contents/{+path}', 'compare_url': 'https://api.github.com/repos/dolphin-emu/dolphin/compare/{base}...{head}', 'merges_url': 'https://api.github.com/repos/dolphin-emu/dolphin/merges', 'archive_url': 'https://api.github.com/repos/dolphin-emu/dolphin/{archive_format}{/ref}', 'downloads_url': 'https://api.github.com/repos/dolphin-emu/dolphin/downloads', 'issues_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues{/number}', 'pulls_url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls{/number}', 'milestones_url': 'https://api.github.com/repos/dolphin-emu/dolphin/milestones{/number}', 'notifications_url': 'https://api.github.com/repos/dolphin-emu/dolphin/notifications{?since,all,participating}', 'labels_url': 'https://api.github.com/repos/dolphin-emu/dolphin/labels{/name}', 'releases_url': 'https://api.github.com/repos/dolphin-emu/dolphin/releases{/id}', 'deployments_url': 'https://api.github.com/repos/dolphin-emu/dolphin/deployments', 'created_at': '2013-07-22T09:07:57Z', 'updated_at': '2026-07-18T18:44:16Z', 'pushed_at': '2026-07-18T10:34:54Z', 'git_url': 'git://github.com/dolphin-emu/dolphin.git', 'ssh_url': 'git@github.com:dolphin-emu/dolphin.git', 'clone_url': 'https://github.com/dolphin-emu/dolphin.git', 'svn_url': 'https://github.com/dolphin-emu/dolphin', 'homepage': 'https://dolphin-emu.org', 'size': 558448, 'stargazers_count': 15272, 'watchers_count': 15272, 'language': 'C++', 'has_issues': False, 'has_projects': False, 'has_downloads': True, 'has_wiki': True, 'has_pages': False, 'has_discussions': False, 'forks_count': 3162, 'mirror_url': None, 'archived': False, 'disabled': False, 'open_issues_count': 446, 'license': {'key': 'other', 'name': 'Other', 'spdx_id': 'NOASSERTION', 'url': None, 'node_id': 'MDc6TGljZW5zZTA='}, 'allow_forking': True, 'is_template': False, 'web_commit_signoff_required': False, 'has_pull_requests': True, 'pull_request_creation_policy': 'all', 'topics': ['cpp', 'emulation', 'emulator', 'gamecube', 'wii'], 'visibility': 'public', 'forks': 3162, 'open_issues': 446, 'watchers': 15272, 'default_branch': 'master', 'custom_properties': {}}, 'organization': {'login': 'dolphin-emu', 'id': 5050316, 'node_id': 'MDEyOk9yZ2FuaXphdGlvbjUwNTAzMTY=', 'url': 'https://api.github.com/orgs/dolphin-emu', 'repos_url': 'https://api.github.com/orgs/dolphin-emu/repos', 'events_url': 'https://api.github.com/orgs/dolphin-emu/events', 'hooks_url': 'https://api.github.com/orgs/dolphin-emu/hooks', 'issues_url': 'https://api.github.com/orgs/dolphin-emu/issues', 'members_url': 'https://api.github.com/orgs/dolphin-emu/members{/member}', 'public_members_url': 'https://api.github.com/orgs/dolphin-emu/public_members{/member}', 'avatar_url': 'https://avatars.githubusercontent.com/u/5050316?v=4', 'description': ''}, 'sender': {'login': 'phire', 'id': 138484, 'node_id': 'MDQ6VXNlcjEzODQ4NA==', 'avatar_url': 'https://avatars.githubusercontent.com/u/138484?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/phire', 'html_url': 'https://github.com/phire', 'followers_url': 'https://api.github.com/users/phire/followers', 'following_url': 'https://api.github.com/users/phire/following{/other_user}', 'gists_url': 'https://api.github.com/users/phire/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/phire/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/phire/subscriptions', 'organizations_url': 'https://api.github.com/users/phire/orgs', 'repos_url': 'https://api.github.com/users/phire/repos', 'events_url': 'https://api.github.com/users/phire/events{/privacy}', 'received_events_url': 'https://api.github.com/users/phire/received_events', 'type': 'User', 'user_view_type': 'public', 'site_admin': False}, 'installation': {'id': 35437981, 'node_id': 'MDIzOkludGVncmF0aW9uSW5zdGFsbGF0aW9uMzU0Mzc5ODE='}}, 'type': 'raw_gh_hook'}
2026-07-18T22:26:25.597109	{'source': 'webserver', 'gh_type': 'pull_request_review_comment', 'raw': {'action': 'created', 'comment': {'url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/comments/3609296950', 'pull_request_review_id': 4729322283, 'id': 3609296950, 'node_id': 'PRRC_kwDOALCn2M7XIYA2', 'diff_hunk': '@@ -186,7 +380,304 @@ std::unique_ptr<WbfsFileReader> WbfsFileReader::Create(File::DirectIOFile file,\n   if (!reader->IsGood())\n     reader.reset();\n \n+  if (reader && reader->m_has_nkit_header)\n+    reader->ReadPartitionInfo();\n+\n   return reader;\n }\n \n+// Converts any disc image to WBFS with an NKit v2 header for lossless round-trips.\n+// Strips disc-level junk and partition-level junk (encrypted sectors whose decrypted\n+// content is zero or LFG padding), records a junk bitmap for reconstruction.\n+// See: https://github.com/dolphin-emu/dolphin/pull/14731\n+bool ConvertToWBFS(BlobReader* infile, const std::string& infile_path,\n+                   const std::string& outfile_path, const CompressCB& callback)\n+{\n+  ASSERT(infile->GetDataSizeType() == DataSizeType::Accurate ||\n+         infile->GetDataSizeType() == DataSizeType::UpperBound);\n+\n+  File::DirectIOFile outfile(outfile_path, File::AccessMode::Write);\n+  if (!outfile.IsOpen())\n+  {\n+    PanicAlertFmtT(\n+        "Failed to open the output file \\"{0}\\".\\n"\n+        "Check that you have permissions to write the target folder and that the media can "\n+        "be written.",\n+        outfile_path);\n+    return false;\n+  }\n+\n+  const u64 disc_size = infile->GetDataSize();\n+\n+  // These match the values used by standard WBFS tools (wwt, WBFS Manager)\n+  static constexpr u8 hd_sector_shift = 9;\n+  static constexpr u8 wbfs_sector_shift = 21;\n+  static constexpr u64 hd_sector_size = 1ull << hd_sector_shift;\n+  static constexpr u64 wbfs_sector_size = 1ull << wbfs_sector_shift;\n+\n+  const u64 blocks_per_disc = (disc_size + wbfs_sector_size - 1) / wbfs_sector_size;\n+  const u64 disc_info_size =\n+      Common::AlignUp(WII_DISC_HEADER_SIZE + blocks_per_disc * sizeof(u16), hd_sector_size);\n+\n+  // Read disc header (first 256 bytes contain disc_id, disc_num, title, etc.)\n+  std::vector<u8> disc_header(WII_DISC_HEADER_SIZE, 0);\n+  if (!infile->Read(0, WII_DISC_HEADER_SIZE, disc_header.data()))\n+  {\n+    PanicAlertFmtT("Failed to read from the input file \\"{0}\\".", infile_path);\n+    return false;\n+  }\n+\n+  // Use Volume for partition info and decrypted reads\n+  struct PartitionInfo\n+  {\n+    u64 data_offset;\n+    u64 data_size;\n+    Partition partition;\n+  };\n+  std::vector<PartitionInfo> partitions;\n+\n+  std::unique_ptr<VolumeDisc> volume = CreateDisc(infile_path);\n+  if (volume)\n+  {\n+    for (const Partition& partition : volume->GetPartitions())\n+    {\n+      const std::optional<u64> data_offset =\n+          volume->ReadSwappedAndShifted(partition.offset + 0x2B8, PARTITION_NONE);\n+      const std::optional<u64> data_size =\n+          volume->ReadSwappedAndShifted(partition.offset + 0x2BC, PARTITION_NONE);\n+      if (!data_offset || !data_size)\n+        continue;\n+\n+      PartitionInfo info;\n+      info.data_offset = partition.offset + *data_offset;\n+      info.data_size = *data_size;\n+      info.partition = partition;\n+      partitions.push_back(info);\n+    }\n+  }\n+\n+  // NKit v2 gap type bitmap: 1 bit per block, MSB-first, always sized for dual-layer\n+  const u64 gap_type_blocks = (DL_DVD_SIZE + wbfs_sector_size - 1) / wbfs_sector_size;\n+  const u64 gap_type_bytes = (gap_type_blocks + 7) / 8;\n+  std::vector<u8> gap_type(gap_type_bytes, 0);\n+\n+  // Compute data_start up front so we can write sectors during the scan\n+  const u64 data_start = Common::AlignUp(hd_sector_size + disc_info_size, wbfs_sector_size);\n+  const u16 wlba_base = static_cast<u16>(data_start / wbfs_sector_size);\n+\n+  // Single pass: scan, classify, hash, and write used sectors in one loop\n+  std::vector<u8> sector_buf(wbfs_sector_size, 0);\n+  std::vector<u16> wlba_table(blocks_per_disc, 0);\n+  u16 used_count = 0;\n+\n+  // NKit v2 stores four hash digests for verification\n+  auto sha1_ctx = Common::SHA1::CreateContext();\n+  u32 crc = Common::StartCRC32();\n+  mbedtls_md5_context md5_ctx{};\n+  mbedtls_md5_init(&md5_ctx);\n+  mbedtls_md5_starts_ret(&md5_ctx);\n+  XXH64_state_t* xxh_state = XXH64_createState();\n+  XXH64_reset(xxh_state, 0);\n+\n+  for (u64 i = 0; i < blocks_per_disc; i++)\n+  {\n+    if (i % 100 == 0)\n+    {\n+      const bool was_cancelled =\n+          !callback(Common::GetStringT("Converting"),\n+                    static_cast<float>(i) / static_cast<float>(blocks_per_disc));\n+      if (was_cancelled)\n+      {\n+        XXH64_freeState(xxh_state);\n+        mbedtls_md5_free(&md5_ctx);\n+        outfile.Close();\n+        File::Delete(outfile_path);\n+        return false;\n+      }\n+    }\n+\n+    const u64 offset = i * wbfs_sector_size;\n+    const size_t sz = static_cast<size_t>(std::min(wbfs_sector_size, disc_size - offset));\n+\n+    if (!infile->Read(offset, sz, sector_buf.data()))\n+    {\n+      PanicAlertFmtT("Failed to read from the input file \\"{0}\\".", infile_path);\n+      XXH64_freeState(xxh_state);\n+      mbedtls_md5_free(&md5_ctx);\n+      outfile.Close();\n+      File::Delete(outfile_path);\n+      return false;\n+    }\n+\n+    // Update all four hashes with the full disc data\n+    sha1_ctx->Update(sector_buf.data(), sz);\n+    crc = Common::UpdateCRC32(crc, sector_buf.data(), sz);\n+    mbedtls_md5_update_ret(&md5_ctx, sector_buf.data(), sz);\n+    XXH64_update(xxh_state, sector_buf.data(), sz);\n+\n+    // Find which partition (if any) this block belongs to\n+    const u32 start_sector = static_cast<u32>(offset / VolumeWii::BLOCK_TOTAL_SIZE);\n+    const u32 end_sector = static_cast<u32>((offset + sz) / VolumeWii::BLOCK_TOTAL_SIZE);\n+    const auto it = std::ranges::find_if(partitions, [&](const PartitionInfo& p) {\n+      const u32 p_start = static_cast<u32>(p.data_offset / VolumeWii::BLOCK_TOTAL_SIZE);\n+      const u32 p_end =\n+          static_cast<u32>((p.data_offset + p.data_size) / VolumeWii::BLOCK_TOTAL_SIZE);\n+      return start_sector >= p_start && end_sector <= p_end;\n+    });\n+    const PartitionInfo* pi = (it != partitions.end()) ? &*it : nullptr;\n+\n+    bool is_used = true;\n+\n+    if (pi)\n+    {\n+      // Partition data: use Volume::Read to get decrypted data for junk/zero checks.\n+      // All-zero and all-junk are checked separately - mixed blocks are stored.\n+      bool all_zero = true;\n+      bool all_junk = true;\n+      for (u64 sub = 0; sub < sz; sub += VolumeWii::BLOCK_TOTAL_SIZE)\n+      {\n+        const u64 abs = offset + sub;\n+        const u64 sector_in_partition = (abs - pi->data_offset) / VolumeWii::BLOCK_TOTAL_SIZE;\n+        const u64 partition_offset = sector_in_partition * VolumeWii::BLOCK_DATA_SIZE;\n+\n+        u8 decrypted[VolumeWii::BLOCK_DATA_SIZE];\n+        if (!volume->Read(partition_offset, VolumeWii::BLOCK_DATA_SIZE, decrypted, pi->partition))\n+          break;\n+\n+        const bool sector_zero = std::ranges::all_of(decrypted, [](u8 b) { return b == 0; });\n+        if (!sector_zero)\n+        {\n+          all_zero = false;\n+          const bool sector_junk = LaggedFibonacciGenerator::IsJunkBlock(\n+              decrypted, VolumeWii::BLOCK_DATA_SIZE, partition_offset, disc_header.data(),\n+              disc_header[6]);\n+          if (!sector_junk)\n+            all_junk = false;\n+        }\n+\n+        if (!all_zero && !all_junk)\n+          break;\n+      }\n+\n+      if (all_zero || all_junk)\n+      {\n+        if (all_junk && !all_zero)\n+          gap_type[i / 8] |= static_cast<u8>(1 << (7 - (i & 7)));\n+        is_used = false;\n+      }\n+    }\n+    else\n+    {\n+      // Non-partition data: check disc-level zero and junk patterns\n+      const bool is_zero = std::ranges::all_of(sector_buf, [](u8 b) { return b == 0; });\n+      if (is_zero)\n+      {\n+        is_used = false;\n+      }\n+      else if (LaggedFibonacciGenerator::IsJunkBlock(sector_buf.data(), sz, offset,\n+                                                     disc_header.data(), disc_header[6]))\n+      {\n+        gap_type[i / 8] |= static_cast<u8>(1 << (7 - (i & 7)));\n+        is_used = false;\n+      }\n+    }\n+\n+    if (is_used)\n+    {\n+      // Write sector directly to output\n+      const u64 out_offset = data_start + static_cast<u64>(used_count) * wbfs_sector_size;\n+      outfile.Seek(out_offset, File::SeekOrigin::Begin);\n+      std::fill(sector_buf.begin() + sz, sector_buf.end(), u8{0});\n+      if (!outfile.Write(sector_buf.data(), wbfs_sector_size))\n+      {\n+        PanicAlertFmtT("Failed to write the output file \\"{0}\\".\\n"\n+                       "Check that you have enough space available on the target drive.",\n+                       outfile_path);\n+        XXH64_freeState(xxh_state);\n+        mbedtls_md5_free(&md5_ctx);\n+        outfile.Close();\n+        File::Delete(outfile_path);\n+        return false;\n+      }\n+\n+      wlba_table[i] = Common::swap16(static_cast<u16>(wlba_base + used_count));\n+      used_count++;\n+    }\n+  }\n+\n+  // Finalize hashes\n+  const Common::SHA1::Digest sha1_digest = sha1_ctx->Finish();\n+  const u64 xxh_digest = XXH64_digest(xxh_state);\n+  XXH64_freeState(xxh_state);\n+\n+  // Write WBFS header (seek back to start)\n+  const u64 total_size = data_start + static_cast<u64>(used_count) * wbfs_sector_size;\n+  const u32 hd_sector_count = static_cast<u32>(total_size / hd_sector_size);\n+\n+  WbfsHeader header{};\n+  header.magic = WBFS_MAGIC;\n+  header.hd_sector_count = Common::swap32(hd_sector_count);\n+  header.hd_sector_shift = hd_sector_shift;\n+  header.wbfs_sector_shift = wbfs_sector_shift;\n+  header.disc_table[0] = 1;\n+\n+  outfile.Seek(0, File::SeekOrigin::Begin);\n+  if (!outfile.Write(Common::AsU8Span(header)))\n+  {\n+    PanicAlertFmtT("Failed to write the output file \\"{0}\\".\\n"\n+                   "Check that you have enough space available on the target drive.",\n+                   outfile_path);\n+    outfile.Close();\n+    File::Delete(outfile_path);\n+    return false;\n+  }', 'path': 'Source/Core/DiscIO/WbfsBlob.cpp', 'commit_id': '24b41d58df2315831b74f76b95417f2739d02f9d', 'original_commit_id': '24b41d58df2315831b74f76b95417f2739d02f9d', 'user': {'login': 'phire', 'id': 138484, 'node_id': 'MDQ6VXNlcjEzODQ4NA==', 'avatar_url': 'https://avatars.githubusercontent.com/u/138484?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/phire', 'html_url': 'https://github.com/phire', 'followers_url': 'https://api.github.com/users/phire/followers', 'following_url': 'https://api.github.com/users/phire/following{/other_user}', 'gists_url': 'https://api.github.com/users/phire/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/phire/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/phire/subscriptions', 'organizations_url': 'https://api.github.com/users/phire/orgs', 'repos_url': 'https://api.github.com/users/phire/repos', 'events_url': 'https://api.github.com/users/phire/events{/privacy}', 'received_events_url': 'https://api.github.com/users/phire/received_events', 'type': 'User', 'user_view_type': 'public', 'site_admin': False}, 'body': 'I think this is the job for a lambda.\n\nPut this near the top of the function:\n\n```c++\nauto write_failed_panic [&] {\n  PanicAlertFmtT("Failed to write..... \n  return false;\n};\n```\n\nWhen combined with `Common::ScopeGuard` to handle closing/deleting (as discussed above), you should be able to simplify all these down to:\n\n```c++\nif (!outfile.Write(Common::AsU8Span(header)))\n{\n  return write_failed_panic();\n}\n```', 'created_at': '2026-07-18T22:18:18Z', 'updated_at': '2026-07-18T22:26:23Z', 'html_url': 'https://github.com/dolphin-emu/dolphin/pull/14731#discussion_r3609296950', 'pull_request_url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/14731', '_links': {'self': {'href': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/comments/3609296950'}, 'html': {'href': 'https://github.com/dolphin-emu/dolphin/pull/14731#discussion_r3609296950'}, 'pull_request': {'href': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/14731'}}, 'reactions': {'url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/comments/3609296950/reactions', 'total_count': 0, '+1': 0, '-1': 0, 'laugh': 0, 'hooray': 0, 'confused': 0, 'heart': 0, 'rocket': 0, 'eyes': 0}, 'start_line': 625, 'original_start_line': 625, 'start_side': 'RIGHT', 'line': 633, 'original_line': 633, 'side': 'RIGHT', 'author_association': 'MEMBER', 'original_position': 540, 'position': 540, 'subject_type': 'line'}, 'pull_request': {'url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/14731', 'id': 4056977334, 'node_id': 'PR_kwDOALCn2M7x0I-2', 'html_url': 'https://github.com/dolphin-emu/dolphin/pull/14731', 'diff_url': 'https://github.com/dolphin-emu/dolphin/pull/14731.diff', 'patch_url': 'https://github.com/dolphin-emu/dolphin/pull/14731.patch', 'issue_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/14731', 'number': 14731, 'state': 'open', 'locked': False, 'title': 'Convert To WBFS Support', 'user': {'login': 'thethiny', 'id': 6018214, 'node_id': 'MDQ6VXNlcjYwMTgyMTQ=', 'avatar_url': 'https://avatars.githubusercontent.com/u/6018214?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/thethiny', 'html_url': 'https://github.com/thethiny', 'followers_url': 'https://api.github.com/users/thethiny/followers', 'following_url': 'https://api.github.com/users/thethiny/following{/other_user}', 'gists_url': 'https://api.github.com/users/thethiny/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/thethiny/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/thethiny/subscriptions', 'organizations_url': 'https://api.github.com/users/thethiny/orgs', 'repos_url': 'https://api.github.com/users/thethiny/repos', 'events_url': 'https://api.github.com/users/thethiny/events{/privacy}', 'received_events_url': 'https://api.github.com/users/thethiny/received_events', 'type': 'User', 'user_view_type': 'public', 'site_admin': False}, 'body': "This PR introduces Conversion **to** WBFS support. WBFS is the format that is used by USB Loaders on a real Wii device.\r\n\r\n## Design decisions & hardcoded values\r\nThe writer uses fixed sector sizes that match what [libwbfs (the reference implementation by kwiirk)](https://github.com/kwiirk/wbfs/blob/master/libwbfs/libwbfs.c#L128-L134) computes for a standard single-layer Wii disc. These 2 hardcodes are stable and work correctly across all my testings.\r\n- HD sector shift: 9 (512 bytes)\r\n- WBFS sector shift: 21 (2 MiB)\r\nThese are not configurable via the UI. All existing WBFS tools use these values, and since the aim is to support USB Loaders then this has been tested and it is working on a real Wii.\r\n\r\nConverting from WBFS is not enabled. The existing `WbfsFileReader` reports `DataSizeType::UpperBound`, and `ShouldAllowConversion()` requires `Accurate`. I am able to support this but since it was hardcoded by the Dolphin team I thought a discussion is warranted.\r\n\r\n## Testing\r\n- Verified with DolphinTool header and DolphinTool verify\r\n- Verified with wit FILETYPE and wit DUMP (Wiimm's ISO Tools recognizes valid WBFS structure, partitions, encryption)\r\n- Tested ISO to WBFS and RVZ to WBFS conversions\r\n- Output file sizes match Wii Backup Manager when scrubbing is enabled (~0.1% difference), works when scrubbing is disabled.\r\n- Output WBFS files play correctly in Dolphin\r\n- Output WBFS files play correctly on a real Wii using USB Loader GX e25c4f3\r\n", 'created_at': '2026-07-15T01:16:25Z', 'updated_at': '2026-07-18T22:16:59Z', 'closed_at': None, 'merged_at': None, 'merge_commit_sha': '228f93416dd80eb09da834ad7852c8eaa4d9212b', 'assignees': [], 'requested_reviewers': [], 'requested_teams': [], 'labels': [], 'milestone': None, 'draft': False, 'commits_url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/14731/commits', 'review_comments_url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/14731/comments', 'review_comment_url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/comments{/number}', 'comments_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/14731/comments', 'statuses_url': 'https://api.github.com/repos/dolphin-emu/dolphin/statuses/24b41d58df2315831b74f76b95417f2739d02f9d', 'head': {'label': 'thethiny:wbfs-conversion', 'ref': 'wbfs-conversion', 'sha': '24b41d58df2315831b74f76b95417f2739d02f9d', 'user': {'login': 'thethiny', 'id': 6018214, 'node_id': 'MDQ6VXNlcjYwMTgyMTQ=', 'avatar_url': 'https://avatars.githubusercontent.com/u/6018214?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/thethiny', 'html_url': 'https://github.com/thethiny', 'followers_url': 'https://api.github.com/users/thethiny/followers', 'following_url': 'https://api.github.com/users/thethiny/following{/other_user}', 'gists_url': 'https://api.github.com/users/thethiny/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/thethiny/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/thethiny/subscriptions', 'organizations_url': 'https://api.github.com/users/thethiny/orgs', 'repos_url': 'https://api.github.com/users/thethiny/repos', 'events_url': 'https://api.github.com/users/thethiny/events{/privacy}', 'received_events_url': 'https://api.github.com/users/thethiny/received_events', 'type': 'User', 'user_view_type': 'public', 'site_admin': False}, 'repo': {'id': 1298654395, 'node_id': 'R_kgDOTWfkuw', 'name': 'dolphin', 'full_name': 'thethiny/dolphin', 'private': False, 'owner': {'login': 'thethiny', 'id': 6018214, 'node_id': 'MDQ6VXNlcjYwMTgyMTQ=', 'avatar_url': 'https://avatars.githubusercontent.com/u/6018214?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/thethiny', 'html_url': 'https://github.com/thethiny', 'followers_url': 'https://api.github.com/users/thethiny/followers', 'following_url': 'https://api.github.com/users/thethiny/following{/other_user}', 'gists_url': 'https://api.github.com/users/thethiny/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/thethiny/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/thethiny/subscriptions', 'organizations_url': 'https://api.github.com/users/thethiny/orgs', 'repos_url': 'https://api.github.com/users/thethiny/repos', 'events_url': 'https://api.github.com/users/thethiny/events{/privacy}', 'received_events_url': 'https://api.github.com/users/thethiny/received_events', 'type': 'User', 'user_view_type': 'public', 'site_admin': False}, 'html_url': 'https://github.com/thethiny/dolphin', 'description': 'Dolphin is a GameCube / Wii emulator, allowing you to play games for these two platforms on PC with improvements.', 'fork': True, 'url': 'https://api.github.com/repos/thethiny/dolphin', 'forks_url': 'https://api.github.com/repos/thethiny/dolphin/forks', 'keys_url': 'https://api.github.com/repos/thethiny/dolphin/keys{/key_id}', 'collaborators_url': 'https://api.github.com/repos/thethiny/dolphin/collaborators{/collaborator}', 'teams_url': 'https://api.github.com/repos/thethiny/dolphin/teams', 'hooks_url': 'https://api.github.com/repos/thethiny/dolphin/hooks', 'issue_events_url': 'https://api.github.com/repos/thethiny/dolphin/issues/events{/number}', 'events_url': 'https://api.github.com/repos/thethiny/dolphin/events', 'assignees_url': 'https://api.github.com/repos/thethiny/dolphin/assignees{/user}', 'branches_url': 'https://api.github.com/repos/thethiny/dolphin/branches{/branch}', 'tags_url': 'https://api.github.com/repos/thethiny/dolphin/tags', 'blobs_url': 'https://api.github.com/repos/thethiny/dolphin/git/blobs{/sha}', 'git_tags_url': 'https://api.github.com/repos/thethiny/dolphin/git/tags{/sha}', 'git_refs_url': 'https://api.github.com/repos/thethiny/dolphin/git/refs{/sha}', 'trees_url': 'https://api.github.com/repos/thethiny/dolphin/git/trees{/sha}', 'statuses_url': 'https://api.github.com/repos/thethiny/dolphin/statuses/{sha}', 'languages_url': 'https://api.github.com/repos/thethiny/dolphin/languages', 'stargazers_url': 'https://api.github.com/repos/thethiny/dolphin/stargazers', 'contributors_url': 'https://api.github.com/repos/thethiny/dolphin/contributors', 'subscribers_url': 'https://api.github.com/repos/thethiny/dolphin/subscribers', 'subscription_url': 'https://api.github.com/repos/thethiny/dolphin/subscription', 'commits_url': 'https://api.github.com/repos/thethiny/dolphin/commits{/sha}', 'git_commits_url': 'https://api.github.com/repos/thethiny/dolphin/git/commits{/sha}', 'comments_url': 'https://api.github.com/repos/thethiny/dolphin/comments{/number}', 'issue_comment_url': 'https://api.github.com/repos/thethiny/dolphin/issues/comments{/number}', 'contents_url': 'https://api.github.com/repos/thethiny/dolphin/contents/{+path}', 'compare_url': 'https://api.github.com/repos/thethiny/dolphin/compare/{base}...{head}', 'merges_url': 'https://api.github.com/repos/thethiny/dolphin/merges', 'archive_url': 'https://api.github.com/repos/thethiny/dolphin/{archive_format}{/ref}', 'downloads_url': 'https://api.github.com/repos/thethiny/dolphin/downloads', 'issues_url': 'https://api.github.com/repos/thethiny/dolphin/issues{/number}', 'pulls_url': 'https://api.github.com/repos/thethiny/dolphin/pulls{/number}', 'milestones_url': 'https://api.github.com/repos/thethiny/dolphin/milestones{/number}', 'notifications_url': 'https://api.github.com/repos/thethiny/dolphin/notifications{?since,all,participating}', 'labels_url': 'https://api.github.com/repos/thethiny/dolphin/labels{/name}', 'releases_url': 'https://api.github.com/repos/thethiny/dolphin/releases{/id}', 'deployments_url': 'https://api.github.com/repos/thethiny/dolphin/deployments', 'created_at': '2026-07-12T22:09:13Z', 'updated_at': '2026-07-12T22:09:13Z', 'pushed_at': '2026-07-18T20:35:03Z', 'git_url': 'git://github.com/thethiny/dolphin.git', 'ssh_url': 'git@github.com:thethiny/dolphin.git', 'clone_url': 'https://github.com/thethiny/dolphin.git', 'svn_url': 'https://github.com/thethiny/dolphin', 'homepage': 'https://dolphin-emu.org', 'size': 515471, 'stargazers_count': 0, 'watchers_count': 0, 'language': None, 'has_issues': False, 'has_projects': True, 'has_downloads': True, 'has_wiki': True, 'has_pages': False, 'has_discussions': False, 'forks_count': 0, 'mirror_url': None, 'archived': False, 'disabled': False, 'open_issues_count': 0, 'license': {'key': 'other', 'name': 'Other', 'spdx_id': 'NOASSERTION', 'url': None, 'node_id': 'MDc6TGljZW5zZTA='}, 'allow_forking': True, 'is_template': False, 'web_commit_signoff_required': False, 'has_pull_requests': True, 'pull_request_creation_policy': 'all', 'topics': [], 'visibility': 'public', 'forks': 0, 'open_issues': 0, 'watchers': 0, 'default_branch': 'master', 'allow_squash_merge': True, 'allow_merge_commit': True, 'allow_rebase_merge': True, 'allow_auto_merge': False, 'delete_branch_on_merge': False, 'allow_update_branch': False, 'use_squash_pr_title_as_default': False, 'squash_merge_commit_message': 'COMMIT_MESSAGES', 'squash_merge_commit_title': 'COMMIT_OR_PR_TITLE', 'merge_commit_message': 'PR_TITLE', 'merge_commit_title': 'MERGE_MESSAGE'}}, 'base': {'label': 'dolphin-emu:master', 'ref': 'master', 'sha': 'd3b2943807dd0073f7767947466dd73cccfef319', 'user': {'login': 'dolphin-emu', 'id': 5050316, 'node_id': 'MDEyOk9yZ2FuaXphdGlvbjUwNTAzMTY=', 'avatar_url': 'https://avatars.githubusercontent.com/u/5050316?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/dolphin-emu', 'html_url': 'https://github.com/dolphin-emu', 'followers_url': 'https://api.github.com/users/dolphin-emu/followers', 'following_url': 'https://api.github.com/users/dolphin-emu/following{/other_user}', 'gists_url': 'https://api.github.com/users/dolphin-emu/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/dolphin-emu/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/dolphin-emu/subscriptions', 'organizations_url': 'https://api.github.com/users/dolphin-emu/orgs', 'repos_url': 'https://api.github.com/users/dolphin-emu/repos', 'events_url': 'https://api.github.com/users/dolphin-emu/events{/privacy}', 'received_events_url': 'https://api.github.com/users/dolphin-emu/received_events', 'type': 'Organization', 'user_view_type': 'public', 'site_admin': False}, 'repo': {'id': 11577304, 'node_id': 'MDEwOlJlcG9zaXRvcnkxMTU3NzMwNA==', 'name': 'dolphin', 'full_name': 'dolphin-emu/dolphin', 'private': False, 'owner': {'login': 'dolphin-emu', 'id': 5050316, 'node_id': 'MDEyOk9yZ2FuaXphdGlvbjUwNTAzMTY=', 'avatar_url': 'https://avatars.githubusercontent.com/u/5050316?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/dolphin-emu', 'html_url': 'https://github.com/dolphin-emu', 'followers_url': 'https://api.github.com/users/dolphin-emu/followers', 'following_url': 'https://api.github.com/users/dolphin-emu/following{/other_user}', 'gists_url': 'https://api.github.com/users/dolphin-emu/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/dolphin-emu/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/dolphin-emu/subscriptions', 'organizations_url': 'https://api.github.com/users/dolphin-emu/orgs', 'repos_url': 'https://api.github.com/users/dolphin-emu/repos', 'events_url': 'https://api.github.com/users/dolphin-emu/events{/privacy}', 'received_events_url': 'https://api.github.com/users/dolphin-emu/received_events', 'type': 'Organization', 'user_view_type': 'public', 'site_admin': False}, 'html_url': 'https://github.com/dolphin-emu/dolphin', 'description': 'Dolphin is a GameCube / Wii emulator, allowing you to play games for these two platforms on PC with improvements.', 'fork': False, 'url': 'https://api.github.com/repos/dolphin-emu/dolphin', 'forks_url': 'https://api.github.com/repos/dolphin-emu/dolphin/forks', 'keys_url': 'https://api.github.com/repos/dolphin-emu/dolphin/keys{/key_id}', 'collaborators_url': 'https://api.github.com/repos/dolphin-emu/dolphin/collaborators{/collaborator}', 'teams_url': 'https://api.github.com/repos/dolphin-emu/dolphin/teams', 'hooks_url': 'https://api.github.com/repos/dolphin-emu/dolphin/hooks', 'issue_events_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/events{/number}', 'events_url': 'https://api.github.com/repos/dolphin-emu/dolphin/events', 'assignees_url': 'https://api.github.com/repos/dolphin-emu/dolphin/assignees{/user}', 'branches_url': 'https://api.github.com/repos/dolphin-emu/dolphin/branches{/branch}', 'tags_url': 'https://api.github.com/repos/dolphin-emu/dolphin/tags', 'blobs_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/blobs{/sha}', 'git_tags_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/tags{/sha}', 'git_refs_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/refs{/sha}', 'trees_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/trees{/sha}', 'statuses_url': 'https://api.github.com/repos/dolphin-emu/dolphin/statuses/{sha}', 'languages_url': 'https://api.github.com/repos/dolphin-emu/dolphin/languages', 'stargazers_url': 'https://api.github.com/repos/dolphin-emu/dolphin/stargazers', 'contributors_url': 'https://api.github.com/repos/dolphin-emu/dolphin/contributors', 'subscribers_url': 'https://api.github.com/repos/dolphin-emu/dolphin/subscribers', 'subscription_url': 'https://api.github.com/repos/dolphin-emu/dolphin/subscription', 'commits_url': 'https://api.github.com/repos/dolphin-emu/dolphin/commits{/sha}', 'git_commits_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/commits{/sha}', 'comments_url': 'https://api.github.com/repos/dolphin-emu/dolphin/comments{/number}', 'issue_comment_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/comments{/number}', 'contents_url': 'https://api.github.com/repos/dolphin-emu/dolphin/contents/{+path}', 'compare_url': 'https://api.github.com/repos/dolphin-emu/dolphin/compare/{base}...{head}', 'merges_url': 'https://api.github.com/repos/dolphin-emu/dolphin/merges', 'archive_url': 'https://api.github.com/repos/dolphin-emu/dolphin/{archive_format}{/ref}', 'downloads_url': 'https://api.github.com/repos/dolphin-emu/dolphin/downloads', 'issues_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues{/number}', 'pulls_url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls{/number}', 'milestones_url': 'https://api.github.com/repos/dolphin-emu/dolphin/milestones{/number}', 'notifications_url': 'https://api.github.com/repos/dolphin-emu/dolphin/notifications{?since,all,participating}', 'labels_url': 'https://api.github.com/repos/dolphin-emu/dolphin/labels{/name}', 'releases_url': 'https://api.github.com/repos/dolphin-emu/dolphin/releases{/id}', 'deployments_url': 'https://api.github.com/repos/dolphin-emu/dolphin/deployments', 'created_at': '2013-07-22T09:07:57Z', 'updated_at': '2026-07-18T18:44:16Z', 'pushed_at': '2026-07-18T10:34:54Z', 'git_url': 'git://github.com/dolphin-emu/dolphin.git', 'ssh_url': 'git@github.com:dolphin-emu/dolphin.git', 'clone_url': 'https://github.com/dolphin-emu/dolphin.git', 'svn_url': 'https://github.com/dolphin-emu/dolphin', 'homepage': 'https://dolphin-emu.org', 'size': 558448, 'stargazers_count': 15272, 'watchers_count': 15272, 'language': 'C++', 'has_issues': False, 'has_projects': False, 'has_downloads': True, 'has_wiki': True, 'has_pages': False, 'has_discussions': False, 'forks_count': 3162, 'mirror_url': None, 'archived': False, 'disabled': False, 'open_issues_count': 446, 'license': {'key': 'other', 'name': 'Other', 'spdx_id': 'NOASSERTION', 'url': None, 'node_id': 'MDc6TGljZW5zZTA='}, 'allow_forking': True, 'is_template': False, 'web_commit_signoff_required': False, 'has_pull_requests': True, 'pull_request_creation_policy': 'all', 'topics': ['cpp', 'emulation', 'emulator', 'gamecube', 'wii'], 'visibility': 'public', 'forks': 3162, 'open_issues': 446, 'watchers': 15272, 'default_branch': 'master', 'allow_squash_merge': False, 'allow_merge_commit': True, 'allow_rebase_merge': False, 'allow_auto_merge': False, 'delete_branch_on_merge': False, 'allow_update_branch': False, 'use_squash_pr_title_as_default': False, 'squash_merge_commit_message': 'COMMIT_MESSAGES', 'squash_merge_commit_title': 'COMMIT_OR_PR_TITLE', 'merge_commit_message': 'PR_TITLE', 'merge_commit_title': 'MERGE_MESSAGE'}}, '_links': {'self': {'href': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/14731'}, 'html': {'href': 'https://github.com/dolphin-emu/dolphin/pull/14731'}, 'issue': {'href': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/14731'}, 'comments': {'href': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/14731/comments'}, 'review_comments': {'href': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/14731/comments'}, 'review_comment': {'href': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/comments{/number}'}, 'commits': {'href': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/14731/commits'}, 'statuses': {'href': 'https://api.github.com/repos/dolphin-emu/dolphin/statuses/24b41d58df2315831b74f76b95417f2739d02f9d'}}, 'author_association': 'NONE', 'auto_merge': None, 'assignee': None, 'active_lock_reason': None}, 'repository': {'id': 11577304, 'node_id': 'MDEwOlJlcG9zaXRvcnkxMTU3NzMwNA==', 'name': 'dolphin', 'full_name': 'dolphin-emu/dolphin', 'private': False, 'owner': {'login': 'dolphin-emu', 'id': 5050316, 'node_id': 'MDEyOk9yZ2FuaXphdGlvbjUwNTAzMTY=', 'avatar_url': 'https://avatars.githubusercontent.com/u/5050316?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/dolphin-emu', 'html_url': 'https://github.com/dolphin-emu', 'followers_url': 'https://api.github.com/users/dolphin-emu/followers', 'following_url': 'https://api.github.com/users/dolphin-emu/following{/other_user}', 'gists_url': 'https://api.github.com/users/dolphin-emu/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/dolphin-emu/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/dolphin-emu/subscriptions', 'organizations_url': 'https://api.github.com/users/dolphin-emu/orgs', 'repos_url': 'https://api.github.com/users/dolphin-emu/repos', 'events_url': 'https://api.github.com/users/dolphin-emu/events{/privacy}', 'received_events_url': 'https://api.github.com/users/dolphin-emu/received_events', 'type': 'Organization', 'user_view_type': 'public', 'site_admin': False}, 'html_url': 'https://github.com/dolphin-emu/dolphin', 'description': 'Dolphin is a GameCube / Wii emulator, allowing you to play games for these two platforms on PC with improvements.', 'fork': False, 'url': 'https://api.github.com/repos/dolphin-emu/dolphin', 'forks_url': 'https://api.github.com/repos/dolphin-emu/dolphin/forks', 'keys_url': 'https://api.github.com/repos/dolphin-emu/dolphin/keys{/key_id}', 'collaborators_url': 'https://api.github.com/repos/dolphin-emu/dolphin/collaborators{/collaborator}', 'teams_url': 'https://api.github.com/repos/dolphin-emu/dolphin/teams', 'hooks_url': 'https://api.github.com/repos/dolphin-emu/dolphin/hooks', 'issue_events_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/events{/number}', 'events_url': 'https://api.github.com/repos/dolphin-emu/dolphin/events', 'assignees_url': 'https://api.github.com/repos/dolphin-emu/dolphin/assignees{/user}', 'branches_url': 'https://api.github.com/repos/dolphin-emu/dolphin/branches{/branch}', 'tags_url': 'https://api.github.com/repos/dolphin-emu/dolphin/tags', 'blobs_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/blobs{/sha}', 'git_tags_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/tags{/sha}', 'git_refs_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/refs{/sha}', 'trees_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/trees{/sha}', 'statuses_url': 'https://api.github.com/repos/dolphin-emu/dolphin/statuses/{sha}', 'languages_url': 'https://api.github.com/repos/dolphin-emu/dolphin/languages', 'stargazers_url': 'https://api.github.com/repos/dolphin-emu/dolphin/stargazers', 'contributors_url': 'https://api.github.com/repos/dolphin-emu/dolphin/contributors', 'subscribers_url': 'https://api.github.com/repos/dolphin-emu/dolphin/subscribers', 'subscription_url': 'https://api.github.com/repos/dolphin-emu/dolphin/subscription', 'commits_url': 'https://api.github.com/repos/dolphin-emu/dolphin/commits{/sha}', 'git_commits_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/commits{/sha}', 'comments_url': 'https://api.github.com/repos/dolphin-emu/dolphin/comments{/number}', 'issue_comment_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/comments{/number}', 'contents_url': 'https://api.github.com/repos/dolphin-emu/dolphin/contents/{+path}', 'compare_url': 'https://api.github.com/repos/dolphin-emu/dolphin/compare/{base}...{head}', 'merges_url': 'https://api.github.com/repos/dolphin-emu/dolphin/merges', 'archive_url': 'https://api.github.com/repos/dolphin-emu/dolphin/{archive_format}{/ref}', 'downloads_url': 'https://api.github.com/repos/dolphin-emu/dolphin/downloads', 'issues_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues{/number}', 'pulls_url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls{/number}', 'milestones_url': 'https://api.github.com/repos/dolphin-emu/dolphin/milestones{/number}', 'notifications_url': 'https://api.github.com/repos/dolphin-emu/dolphin/notifications{?since,all,participating}', 'labels_url': 'https://api.github.com/repos/dolphin-emu/dolphin/labels{/name}', 'releases_url': 'https://api.github.com/repos/dolphin-emu/dolphin/releases{/id}', 'deployments_url': 'https://api.github.com/repos/dolphin-emu/dolphin/deployments', 'created_at': '2013-07-22T09:07:57Z', 'updated_at': '2026-07-18T18:44:16Z', 'pushed_at': '2026-07-18T10:34:54Z', 'git_url': 'git://github.com/dolphin-emu/dolphin.git', 'ssh_url': 'git@github.com:dolphin-emu/dolphin.git', 'clone_url': 'https://github.com/dolphin-emu/dolphin.git', 'svn_url': 'https://github.com/dolphin-emu/dolphin', 'homepage': 'https://dolphin-emu.org', 'size': 558448, 'stargazers_count': 15272, 'watchers_count': 15272, 'language': 'C++', 'has_issues': False, 'has_projects': False, 'has_downloads': True, 'has_wiki': True, 'has_pages': False, 'has_discussions': False, 'forks_count': 3162, 'mirror_url': None, 'archived': False, 'disabled': False, 'open_issues_count': 446, 'license': {'key': 'other', 'name': 'Other', 'spdx_id': 'NOASSERTION', 'url': None, 'node_id': 'MDc6TGljZW5zZTA='}, 'allow_forking': True, 'is_template': False, 'web_commit_signoff_required': False, 'has_pull_requests': True, 'pull_request_creation_policy': 'all', 'topics': ['cpp', 'emulation', 'emulator', 'gamecube', 'wii'], 'visibility': 'public', 'forks': 3162, 'open_issues': 446, 'watchers': 15272, 'default_branch': 'master', 'custom_properties': {}}, 'organization': {'login': 'dolphin-emu', 'id': 5050316, 'node_id': 'MDEyOk9yZ2FuaXphdGlvbjUwNTAzMTY=', 'url': 'https://api.github.com/orgs/dolphin-emu', 'repos_url': 'https://api.github.com/orgs/dolphin-emu/repos', 'events_url': 'https://api.github.com/orgs/dolphin-emu/events', 'hooks_url': 'https://api.github.com/orgs/dolphin-emu/hooks', 'issues_url': 'https://api.github.com/orgs/dolphin-emu/issues', 'members_url': 'https://api.github.com/orgs/dolphin-emu/members{/member}', 'public_members_url': 'https://api.github.com/orgs/dolphin-emu/public_members{/member}', 'avatar_url': 'https://avatars.githubusercontent.com/u/5050316?v=4', 'description': ''}, 'sender': {'login': 'phire', 'id': 138484, 'node_id': 'MDQ6VXNlcjEzODQ4NA==', 'avatar_url': 'https://avatars.githubusercontent.com/u/138484?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/phire', 'html_url': 'https://github.com/phire', 'followers_url': 'https://api.github.com/users/phire/followers', 'following_url': 'https://api.github.com/users/phire/following{/other_user}', 'gists_url': 'https://api.github.com/users/phire/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/phire/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/phire/subscriptions', 'organizations_url': 'https://api.github.com/users/phire/orgs', 'repos_url': 'https://api.github.com/users/phire/repos', 'events_url': 'https://api.github.com/users/phire/events{/privacy}', 'received_events_url': 'https://api.github.com/users/phire/received_events', 'type': 'User', 'user_view_type': 'public', 'site_admin': False}, 'installation': {'id': 35437981, 'node_id': 'MDIzOkludGVncmF0aW9uSW5zdGFsbGF0aW9uMzU0Mzc5ODE='}}, 'type': 'raw_gh_hook'}
2026-07-18T22:26:25.588222	{'source': 'webserver', 'gh_type': 'pull_request_review_comment', 'raw': {'action': 'created', 'comment': {'url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/comments/3609262932', 'pull_request_review_id': 4729322283, 'id': 3609262932, 'node_id': 'PRRC_kwDOALCn2M7XIPtU', 'diff_hunk': '@@ -186,7 +380,304 @@ std::unique_ptr<WbfsFileReader> WbfsFileReader::Create(File::DirectIOFile file,\n   if (!reader->IsGood())\n     reader.reset();\n \n+  if (reader && reader->m_has_nkit_header)\n+    reader->ReadPartitionInfo();\n+\n   return reader;\n }\n \n+// Converts any disc image to WBFS with an NKit v2 header for lossless round-trips.\n+// Strips disc-level junk and partition-level junk (encrypted sectors whose decrypted\n+// content is zero or LFG padding), records a junk bitmap for reconstruction.\n+// See: https://github.com/dolphin-emu/dolphin/pull/14731\n+bool ConvertToWBFS(BlobReader* infile, const std::string& infile_path,\n+                   const std::string& outfile_path, const CompressCB& callback)\n+{\n+  ASSERT(infile->GetDataSizeType() == DataSizeType::Accurate ||\n+         infile->GetDataSizeType() == DataSizeType::UpperBound);\n+\n+  File::DirectIOFile outfile(outfile_path, File::AccessMode::Write);\n+  if (!outfile.IsOpen())\n+  {\n+    PanicAlertFmtT(\n+        "Failed to open the output file \\"{0}\\".\\n"\n+        "Check that you have permissions to write the target folder and that the media can "\n+        "be written.",\n+        outfile_path);\n+    return false;\n+  }\n+\n+  const u64 disc_size = infile->GetDataSize();\n+\n+  // These match the values used by standard WBFS tools (wwt, WBFS Manager)\n+  static constexpr u8 hd_sector_shift = 9;\n+  static constexpr u8 wbfs_sector_shift = 21;\n+  static constexpr u64 hd_sector_size = 1ull << hd_sector_shift;\n+  static constexpr u64 wbfs_sector_size = 1ull << wbfs_sector_shift;\n+\n+  const u64 blocks_per_disc = (disc_size + wbfs_sector_size - 1) / wbfs_sector_size;\n+  const u64 disc_info_size =\n+      Common::AlignUp(WII_DISC_HEADER_SIZE + blocks_per_disc * sizeof(u16), hd_sector_size);\n+\n+  // Read disc header (first 256 bytes contain disc_id, disc_num, title, etc.)\n+  std::vector<u8> disc_header(WII_DISC_HEADER_SIZE, 0);\n+  if (!infile->Read(0, WII_DISC_HEADER_SIZE, disc_header.data()))\n+  {\n+    PanicAlertFmtT("Failed to read from the input file \\"{0}\\".", infile_path);\n+    return false;\n+  }\n+\n+  // Use Volume for partition info and decrypted reads\n+  struct PartitionInfo\n+  {\n+    u64 data_offset;\n+    u64 data_size;\n+    Partition partition;\n+  };\n+  std::vector<PartitionInfo> partitions;\n+\n+  std::unique_ptr<VolumeDisc> volume = CreateDisc(infile_path);\n+  if (volume)\n+  {\n+    for (const Partition& partition : volume->GetPartitions())\n+    {\n+      const std::optional<u64> data_offset =\n+          volume->ReadSwappedAndShifted(partition.offset + 0x2B8, PARTITION_NONE);\n+      const std::optional<u64> data_size =\n+          volume->ReadSwappedAndShifted(partition.offset + 0x2BC, PARTITION_NONE);\n+      if (!data_offset || !data_size)\n+        continue;\n+\n+      PartitionInfo info;\n+      info.data_offset = partition.offset + *data_offset;\n+      info.data_size = *data_size;\n+      info.partition = partition;\n+      partitions.push_back(info);\n+    }\n+  }\n+\n+  // NKit v2 gap type bitmap: 1 bit per block, MSB-first, always sized for dual-layer\n+  const u64 gap_type_blocks = (DL_DVD_SIZE + wbfs_sector_size - 1) / wbfs_sector_size;\n+  const u64 gap_type_bytes = (gap_type_blocks + 7) / 8;\n+  std::vector<u8> gap_type(gap_type_bytes, 0);\n+\n+  // Compute data_start up front so we can write sectors during the scan\n+  const u64 data_start = Common::AlignUp(hd_sector_size + disc_info_size, wbfs_sector_size);\n+  const u16 wlba_base = static_cast<u16>(data_start / wbfs_sector_size);\n+\n+  // Single pass: scan, classify, hash, and write used sectors in one loop\n+  std::vector<u8> sector_buf(wbfs_sector_size, 0);\n+  std::vector<u16> wlba_table(blocks_per_disc, 0);\n+  u16 used_count = 0;\n+\n+  // NKit v2 stores four hash digests for verification\n+  auto sha1_ctx = Common::SHA1::CreateContext();\n+  u32 crc = Common::StartCRC32();\n+  mbedtls_md5_context md5_ctx{};\n+  mbedtls_md5_init(&md5_ctx);\n+  mbedtls_md5_starts_ret(&md5_ctx);\n+  XXH64_state_t* xxh_state = XXH64_createState();\n+  XXH64_reset(xxh_state, 0);\n+\n+  for (u64 i = 0; i < blocks_per_disc; i++)\n+  {\n+    if (i % 100 == 0)\n+    {\n+      const bool was_cancelled =\n+          !callback(Common::GetStringT("Converting"),\n+                    static_cast<float>(i) / static_cast<float>(blocks_per_disc));\n+      if (was_cancelled)\n+      {\n+        XXH64_freeState(xxh_state);\n+        mbedtls_md5_free(&md5_ctx);\n+        outfile.Close();\n+        File::Delete(outfile_path);\n+        return false;\n+      }\n+    }\n+\n+    const u64 offset = i * wbfs_sector_size;\n+    const size_t sz = static_cast<size_t>(std::min(wbfs_sector_size, disc_size - offset));\n+\n+    if (!infile->Read(offset, sz, sector_buf.data()))\n+    {\n+      PanicAlertFmtT("Failed to read from the input file \\"{0}\\".", infile_path);\n+      XXH64_freeState(xxh_state);\n+      mbedtls_md5_free(&md5_ctx);\n+      outfile.Close();\n+      File::Delete(outfile_path);\n+      return false;\n+    }\n+\n+    // Update all four hashes with the full disc data\n+    sha1_ctx->Update(sector_buf.data(), sz);\n+    crc = Common::UpdateCRC32(crc, sector_buf.data(), sz);\n+    mbedtls_md5_update_ret(&md5_ctx, sector_buf.data(), sz);\n+    XXH64_update(xxh_state, sector_buf.data(), sz);\n+\n+    // Find which partition (if any) this block belongs to\n+    const u32 start_sector = static_cast<u32>(offset / VolumeWii::BLOCK_TOTAL_SIZE);\n+    const u32 end_sector = static_cast<u32>((offset + sz) / VolumeWii::BLOCK_TOTAL_SIZE);\n+    const auto it = std::ranges::find_if(partitions, [&](const PartitionInfo& p) {\n+      const u32 p_start = static_cast<u32>(p.data_offset / VolumeWii::BLOCK_TOTAL_SIZE);\n+      const u32 p_end =\n+          static_cast<u32>((p.data_offset + p.data_size) / VolumeWii::BLOCK_TOTAL_SIZE);\n+      return start_sector >= p_start && end_sector <= p_end;\n+    });\n+    const PartitionInfo* pi = (it != partitions.end()) ? &*it : nullptr;\n+\n+    bool is_used = true;\n+\n+    if (pi)\n+    {\n+      // Partition data: use Volume::Read to get decrypted data for junk/zero checks.\n+      // All-zero and all-junk are checked separately - mixed blocks are stored.\n+      bool all_zero = true;\n+      bool all_junk = true;\n+      for (u64 sub = 0; sub < sz; sub += VolumeWii::BLOCK_TOTAL_SIZE)\n+      {\n+        const u64 abs = offset + sub;\n+        const u64 sector_in_partition = (abs - pi->data_offset) / VolumeWii::BLOCK_TOTAL_SIZE;\n+        const u64 partition_offset = sector_in_partition * VolumeWii::BLOCK_DATA_SIZE;\n+\n+        u8 decrypted[VolumeWii::BLOCK_DATA_SIZE];\n+        if (!volume->Read(partition_offset, VolumeWii::BLOCK_DATA_SIZE, decrypted, pi->partition))\n+          break;\n+\n+        const bool sector_zero = std::ranges::all_of(decrypted, [](u8 b) { return b == 0; });\n+        if (!sector_zero)\n+        {\n+          all_zero = false;\n+          const bool sector_junk = LaggedFibonacciGenerator::IsJunkBlock(\n+              decrypted, VolumeWii::BLOCK_DATA_SIZE, partition_offset, disc_header.data(),\n+              disc_header[6]);\n+          if (!sector_junk)\n+            all_junk = false;\n+        }\n+\n+        if (!all_zero && !all_junk)\n+          break;\n+      }\n+\n+      if (all_zero || all_junk)\n+      {\n+        if (all_junk && !all_zero)\n+          gap_type[i / 8] |= static_cast<u8>(1 << (7 - (i & 7)));\n+        is_used = false;\n+      }\n+    }\n+    else\n+    {\n+      // Non-partition data: check disc-level zero and junk patterns\n+      const bool is_zero = std::ranges::all_of(sector_buf, [](u8 b) { return b == 0; });\n+      if (is_zero)\n+      {\n+        is_used = false;\n+      }\n+      else if (LaggedFibonacciGenerator::IsJunkBlock(sector_buf.data(), sz, offset,\n+                                                     disc_header.data(), disc_header[6]))\n+      {\n+        gap_type[i / 8] |= static_cast<u8>(1 << (7 - (i & 7)));\n+        is_used = false;\n+      }\n+    }\n+\n+    if (is_used)\n+    {\n+      // Write sector directly to output\n+      const u64 out_offset = data_start + static_cast<u64>(used_count) * wbfs_sector_size;\n+      outfile.Seek(out_offset, File::SeekOrigin::Begin);', 'path': 'Source/Core/DiscIO/WbfsBlob.cpp', 'commit_id': '24b41d58df2315831b74f76b95417f2739d02f9d', 'original_commit_id': '24b41d58df2315831b74f76b95417f2739d02f9d', 'user': {'login': 'phire', 'id': 138484, 'node_id': 'MDQ6VXNlcjEzODQ4NA==', 'avatar_url': 'https://avatars.githubusercontent.com/u/138484?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/phire', 'html_url': 'https://github.com/phire', 'followers_url': 'https://api.github.com/users/phire/followers', 'following_url': 'https://api.github.com/users/phire/following{/other_user}', 'gists_url': 'https://api.github.com/users/phire/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/phire/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/phire/subscriptions', 'organizations_url': 'https://api.github.com/users/phire/orgs', 'repos_url': 'https://api.github.com/users/phire/repos', 'events_url': 'https://api.github.com/users/phire/events{/privacy}', 'received_events_url': 'https://api.github.com/users/phire/received_events', 'type': 'User', 'user_view_type': 'public', 'site_admin': False}, 'body': 'Should be able to avoid the seek in the loop.\nJust seek once to `data_start` before the loop, the writes will advance to the next position.  ', 'created_at': '2026-07-18T21:54:25Z', 'updated_at': '2026-07-18T22:26:23Z', 'html_url': 'https://github.com/dolphin-emu/dolphin/pull/14731#discussion_r3609262932', 'pull_request_url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/14731', '_links': {'self': {'href': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/comments/3609262932'}, 'html': {'href': 'https://github.com/dolphin-emu/dolphin/pull/14731#discussion_r3609262932'}, 'pull_request': {'href': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/14731'}}, 'reactions': {'url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/comments/3609262932/reactions', 'total_count': 0, '+1': 0, '-1': 0, 'laugh': 0, 'hooray': 0, 'confused': 0, 'heart': 0, 'rocket': 0, 'eyes': 0}, 'start_line': None, 'original_start_line': None, 'start_side': None, 'line': 589, 'original_line': 589, 'side': 'RIGHT', 'author_association': 'MEMBER', 'original_position': 496, 'position': 496, 'subject_type': 'line'}, 'pull_request': {'url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/14731', 'id': 4056977334, 'node_id': 'PR_kwDOALCn2M7x0I-2', 'html_url': 'https://github.com/dolphin-emu/dolphin/pull/14731', 'diff_url': 'https://github.com/dolphin-emu/dolphin/pull/14731.diff', 'patch_url': 'https://github.com/dolphin-emu/dolphin/pull/14731.patch', 'issue_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/14731', 'number': 14731, 'state': 'open', 'locked': False, 'title': 'Convert To WBFS Support', 'user': {'login': 'thethiny', 'id': 6018214, 'node_id': 'MDQ6VXNlcjYwMTgyMTQ=', 'avatar_url': 'https://avatars.githubusercontent.com/u/6018214?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/thethiny', 'html_url': 'https://github.com/thethiny', 'followers_url': 'https://api.github.com/users/thethiny/followers', 'following_url': 'https://api.github.com/users/thethiny/following{/other_user}', 'gists_url': 'https://api.github.com/users/thethiny/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/thethiny/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/thethiny/subscriptions', 'organizations_url': 'https://api.github.com/users/thethiny/orgs', 'repos_url': 'https://api.github.com/users/thethiny/repos', 'events_url': 'https://api.github.com/users/thethiny/events{/privacy}', 'received_events_url': 'https://api.github.com/users/thethiny/received_events', 'type': 'User', 'user_view_type': 'public', 'site_admin': False}, 'body': "This PR introduces Conversion **to** WBFS support. WBFS is the format that is used by USB Loaders on a real Wii device.\r\n\r\n## Design decisions & hardcoded values\r\nThe writer uses fixed sector sizes that match what [libwbfs (the reference implementation by kwiirk)](https://github.com/kwiirk/wbfs/blob/master/libwbfs/libwbfs.c#L128-L134) computes for a standard single-layer Wii disc. These 2 hardcodes are stable and work correctly across all my testings.\r\n- HD sector shift: 9 (512 bytes)\r\n- WBFS sector shift: 21 (2 MiB)\r\nThese are not configurable via the UI. All existing WBFS tools use these values, and since the aim is to support USB Loaders then this has been tested and it is working on a real Wii.\r\n\r\nConverting from WBFS is not enabled. The existing `WbfsFileReader` reports `DataSizeType::UpperBound`, and `ShouldAllowConversion()` requires `Accurate`. I am able to support this but since it was hardcoded by the Dolphin team I thought a discussion is warranted.\r\n\r\n## Testing\r\n- Verified with DolphinTool header and DolphinTool verify\r\n- Verified with wit FILETYPE and wit DUMP (Wiimm's ISO Tools recognizes valid WBFS structure, partitions, encryption)\r\n- Tested ISO to WBFS and RVZ to WBFS conversions\r\n- Output file sizes match Wii Backup Manager when scrubbing is enabled (~0.1% difference), works when scrubbing is disabled.\r\n- Output WBFS files play correctly in Dolphin\r\n- Output WBFS files play correctly on a real Wii using USB Loader GX e25c4f3\r\n", 'created_at': '2026-07-15T01:16:25Z', 'updated_at': '2026-07-18T22:16:59Z', 'closed_at': None, 'merged_at': None, 'merge_commit_sha': '228f93416dd80eb09da834ad7852c8eaa4d9212b', 'assignees': [], 'requested_reviewers': [], 'requested_teams': [], 'labels': [], 'milestone': None, 'draft': False, 'commits_url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/14731/commits', 'review_comments_url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/14731/comments', 'review_comment_url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/comments{/number}', 'comments_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/14731/comments', 'statuses_url': 'https://api.github.com/repos/dolphin-emu/dolphin/statuses/24b41d58df2315831b74f76b95417f2739d02f9d', 'head': {'label': 'thethiny:wbfs-conversion', 'ref': 'wbfs-conversion', 'sha': '24b41d58df2315831b74f76b95417f2739d02f9d', 'user': {'login': 'thethiny', 'id': 6018214, 'node_id': 'MDQ6VXNlcjYwMTgyMTQ=', 'avatar_url': 'https://avatars.githubusercontent.com/u/6018214?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/thethiny', 'html_url': 'https://github.com/thethiny', 'followers_url': 'https://api.github.com/users/thethiny/followers', 'following_url': 'https://api.github.com/users/thethiny/following{/other_user}', 'gists_url': 'https://api.github.com/users/thethiny/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/thethiny/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/thethiny/subscriptions', 'organizations_url': 'https://api.github.com/users/thethiny/orgs', 'repos_url': 'https://api.github.com/users/thethiny/repos', 'events_url': 'https://api.github.com/users/thethiny/events{/privacy}', 'received_events_url': 'https://api.github.com/users/thethiny/received_events', 'type': 'User', 'user_view_type': 'public', 'site_admin': False}, 'repo': {'id': 1298654395, 'node_id': 'R_kgDOTWfkuw', 'name': 'dolphin', 'full_name': 'thethiny/dolphin', 'private': False, 'owner': {'login': 'thethiny', 'id': 6018214, 'node_id': 'MDQ6VXNlcjYwMTgyMTQ=', 'avatar_url': 'https://avatars.githubusercontent.com/u/6018214?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/thethiny', 'html_url': 'https://github.com/thethiny', 'followers_url': 'https://api.github.com/users/thethiny/followers', 'following_url': 'https://api.github.com/users/thethiny/following{/other_user}', 'gists_url': 'https://api.github.com/users/thethiny/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/thethiny/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/thethiny/subscriptions', 'organizations_url': 'https://api.github.com/users/thethiny/orgs', 'repos_url': 'https://api.github.com/users/thethiny/repos', 'events_url': 'https://api.github.com/users/thethiny/events{/privacy}', 'received_events_url': 'https://api.github.com/users/thethiny/received_events', 'type': 'User', 'user_view_type': 'public', 'site_admin': False}, 'html_url': 'https://github.com/thethiny/dolphin', 'description': 'Dolphin is a GameCube / Wii emulator, allowing you to play games for these two platforms on PC with improvements.', 'fork': True, 'url': 'https://api.github.com/repos/thethiny/dolphin', 'forks_url': 'https://api.github.com/repos/thethiny/dolphin/forks', 'keys_url': 'https://api.github.com/repos/thethiny/dolphin/keys{/key_id}', 'collaborators_url': 'https://api.github.com/repos/thethiny/dolphin/collaborators{/collaborator}', 'teams_url': 'https://api.github.com/repos/thethiny/dolphin/teams', 'hooks_url': 'https://api.github.com/repos/thethiny/dolphin/hooks', 'issue_events_url': 'https://api.github.com/repos/thethiny/dolphin/issues/events{/number}', 'events_url': 'https://api.github.com/repos/thethiny/dolphin/events', 'assignees_url': 'https://api.github.com/repos/thethiny/dolphin/assignees{/user}', 'branches_url': 'https://api.github.com/repos/thethiny/dolphin/branches{/branch}', 'tags_url': 'https://api.github.com/repos/thethiny/dolphin/tags', 'blobs_url': 'https://api.github.com/repos/thethiny/dolphin/git/blobs{/sha}', 'git_tags_url': 'https://api.github.com/repos/thethiny/dolphin/git/tags{/sha}', 'git_refs_url': 'https://api.github.com/repos/thethiny/dolphin/git/refs{/sha}', 'trees_url': 'https://api.github.com/repos/thethiny/dolphin/git/trees{/sha}', 'statuses_url': 'https://api.github.com/repos/thethiny/dolphin/statuses/{sha}', 'languages_url': 'https://api.github.com/repos/thethiny/dolphin/languages', 'stargazers_url': 'https://api.github.com/repos/thethiny/dolphin/stargazers', 'contributors_url': 'https://api.github.com/repos/thethiny/dolphin/contributors', 'subscribers_url': 'https://api.github.com/repos/thethiny/dolphin/subscribers', 'subscription_url': 'https://api.github.com/repos/thethiny/dolphin/subscription', 'commits_url': 'https://api.github.com/repos/thethiny/dolphin/commits{/sha}', 'git_commits_url': 'https://api.github.com/repos/thethiny/dolphin/git/commits{/sha}', 'comments_url': 'https://api.github.com/repos/thethiny/dolphin/comments{/number}', 'issue_comment_url': 'https://api.github.com/repos/thethiny/dolphin/issues/comments{/number}', 'contents_url': 'https://api.github.com/repos/thethiny/dolphin/contents/{+path}', 'compare_url': 'https://api.github.com/repos/thethiny/dolphin/compare/{base}...{head}', 'merges_url': 'https://api.github.com/repos/thethiny/dolphin/merges', 'archive_url': 'https://api.github.com/repos/thethiny/dolphin/{archive_format}{/ref}', 'downloads_url': 'https://api.github.com/repos/thethiny/dolphin/downloads', 'issues_url': 'https://api.github.com/repos/thethiny/dolphin/issues{/number}', 'pulls_url': 'https://api.github.com/repos/thethiny/dolphin/pulls{/number}', 'milestones_url': 'https://api.github.com/repos/thethiny/dolphin/milestones{/number}', 'notifications_url': 'https://api.github.com/repos/thethiny/dolphin/notifications{?since,all,participating}', 'labels_url': 'https://api.github.com/repos/thethiny/dolphin/labels{/name}', 'releases_url': 'https://api.github.com/repos/thethiny/dolphin/releases{/id}', 'deployments_url': 'https://api.github.com/repos/thethiny/dolphin/deployments', 'created_at': '2026-07-12T22:09:13Z', 'updated_at': '2026-07-12T22:09:13Z', 'pushed_at': '2026-07-18T20:35:03Z', 'git_url': 'git://github.com/thethiny/dolphin.git', 'ssh_url': 'git@github.com:thethiny/dolphin.git', 'clone_url': 'https://github.com/thethiny/dolphin.git', 'svn_url': 'https://github.com/thethiny/dolphin', 'homepage': 'https://dolphin-emu.org', 'size': 515471, 'stargazers_count': 0, 'watchers_count': 0, 'language': None, 'has_issues': False, 'has_projects': True, 'has_downloads': True, 'has_wiki': True, 'has_pages': False, 'has_discussions': False, 'forks_count': 0, 'mirror_url': None, 'archived': False, 'disabled': False, 'open_issues_count': 0, 'license': {'key': 'other', 'name': 'Other', 'spdx_id': 'NOASSERTION', 'url': None, 'node_id': 'MDc6TGljZW5zZTA='}, 'allow_forking': True, 'is_template': False, 'web_commit_signoff_required': False, 'has_pull_requests': True, 'pull_request_creation_policy': 'all', 'topics': [], 'visibility': 'public', 'forks': 0, 'open_issues': 0, 'watchers': 0, 'default_branch': 'master', 'allow_squash_merge': True, 'allow_merge_commit': True, 'allow_rebase_merge': True, 'allow_auto_merge': False, 'delete_branch_on_merge': False, 'allow_update_branch': False, 'use_squash_pr_title_as_default': False, 'squash_merge_commit_message': 'COMMIT_MESSAGES', 'squash_merge_commit_title': 'COMMIT_OR_PR_TITLE', 'merge_commit_message': 'PR_TITLE', 'merge_commit_title': 'MERGE_MESSAGE'}}, 'base': {'label': 'dolphin-emu:master', 'ref': 'master', 'sha': 'd3b2943807dd0073f7767947466dd73cccfef319', 'user': {'login': 'dolphin-emu', 'id': 5050316, 'node_id': 'MDEyOk9yZ2FuaXphdGlvbjUwNTAzMTY=', 'avatar_url': 'https://avatars.githubusercontent.com/u/5050316?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/dolphin-emu', 'html_url': 'https://github.com/dolphin-emu', 'followers_url': 'https://api.github.com/users/dolphin-emu/followers', 'following_url': 'https://api.github.com/users/dolphin-emu/following{/other_user}', 'gists_url': 'https://api.github.com/users/dolphin-emu/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/dolphin-emu/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/dolphin-emu/subscriptions', 'organizations_url': 'https://api.github.com/users/dolphin-emu/orgs', 'repos_url': 'https://api.github.com/users/dolphin-emu/repos', 'events_url': 'https://api.github.com/users/dolphin-emu/events{/privacy}', 'received_events_url': 'https://api.github.com/users/dolphin-emu/received_events', 'type': 'Organization', 'user_view_type': 'public', 'site_admin': False}, 'repo': {'id': 11577304, 'node_id': 'MDEwOlJlcG9zaXRvcnkxMTU3NzMwNA==', 'name': 'dolphin', 'full_name': 'dolphin-emu/dolphin', 'private': False, 'owner': {'login': 'dolphin-emu', 'id': 5050316, 'node_id': 'MDEyOk9yZ2FuaXphdGlvbjUwNTAzMTY=', 'avatar_url': 'https://avatars.githubusercontent.com/u/5050316?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/dolphin-emu', 'html_url': 'https://github.com/dolphin-emu', 'followers_url': 'https://api.github.com/users/dolphin-emu/followers', 'following_url': 'https://api.github.com/users/dolphin-emu/following{/other_user}', 'gists_url': 'https://api.github.com/users/dolphin-emu/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/dolphin-emu/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/dolphin-emu/subscriptions', 'organizations_url': 'https://api.github.com/users/dolphin-emu/orgs', 'repos_url': 'https://api.github.com/users/dolphin-emu/repos', 'events_url': 'https://api.github.com/users/dolphin-emu/events{/privacy}', 'received_events_url': 'https://api.github.com/users/dolphin-emu/received_events', 'type': 'Organization', 'user_view_type': 'public', 'site_admin': False}, 'html_url': 'https://github.com/dolphin-emu/dolphin', 'description': 'Dolphin is a GameCube / Wii emulator, allowing you to play games for these two platforms on PC with improvements.', 'fork': False, 'url': 'https://api.github.com/repos/dolphin-emu/dolphin', 'forks_url': 'https://api.github.com/repos/dolphin-emu/dolphin/forks', 'keys_url': 'https://api.github.com/repos/dolphin-emu/dolphin/keys{/key_id}', 'collaborators_url': 'https://api.github.com/repos/dolphin-emu/dolphin/collaborators{/collaborator}', 'teams_url': 'https://api.github.com/repos/dolphin-emu/dolphin/teams', 'hooks_url': 'https://api.github.com/repos/dolphin-emu/dolphin/hooks', 'issue_events_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/events{/number}', 'events_url': 'https://api.github.com/repos/dolphin-emu/dolphin/events', 'assignees_url': 'https://api.github.com/repos/dolphin-emu/dolphin/assignees{/user}', 'branches_url': 'https://api.github.com/repos/dolphin-emu/dolphin/branches{/branch}', 'tags_url': 'https://api.github.com/repos/dolphin-emu/dolphin/tags', 'blobs_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/blobs{/sha}', 'git_tags_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/tags{/sha}', 'git_refs_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/refs{/sha}', 'trees_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/trees{/sha}', 'statuses_url': 'https://api.github.com/repos/dolphin-emu/dolphin/statuses/{sha}', 'languages_url': 'https://api.github.com/repos/dolphin-emu/dolphin/languages', 'stargazers_url': 'https://api.github.com/repos/dolphin-emu/dolphin/stargazers', 'contributors_url': 'https://api.github.com/repos/dolphin-emu/dolphin/contributors', 'subscribers_url': 'https://api.github.com/repos/dolphin-emu/dolphin/subscribers', 'subscription_url': 'https://api.github.com/repos/dolphin-emu/dolphin/subscription', 'commits_url': 'https://api.github.com/repos/dolphin-emu/dolphin/commits{/sha}', 'git_commits_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/commits{/sha}', 'comments_url': 'https://api.github.com/repos/dolphin-emu/dolphin/comments{/number}', 'issue_comment_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/comments{/number}', 'contents_url': 'https://api.github.com/repos/dolphin-emu/dolphin/contents/{+path}', 'compare_url': 'https://api.github.com/repos/dolphin-emu/dolphin/compare/{base}...{head}', 'merges_url': 'https://api.github.com/repos/dolphin-emu/dolphin/merges', 'archive_url': 'https://api.github.com/repos/dolphin-emu/dolphin/{archive_format}{/ref}', 'downloads_url': 'https://api.github.com/repos/dolphin-emu/dolphin/downloads', 'issues_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues{/number}', 'pulls_url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls{/number}', 'milestones_url': 'https://api.github.com/repos/dolphin-emu/dolphin/milestones{/number}', 'notifications_url': 'https://api.github.com/repos/dolphin-emu/dolphin/notifications{?since,all,participating}', 'labels_url': 'https://api.github.com/repos/dolphin-emu/dolphin/labels{/name}', 'releases_url': 'https://api.github.com/repos/dolphin-emu/dolphin/releases{/id}', 'deployments_url': 'https://api.github.com/repos/dolphin-emu/dolphin/deployments', 'created_at': '2013-07-22T09:07:57Z', 'updated_at': '2026-07-18T18:44:16Z', 'pushed_at': '2026-07-18T10:34:54Z', 'git_url': 'git://github.com/dolphin-emu/dolphin.git', 'ssh_url': 'git@github.com:dolphin-emu/dolphin.git', 'clone_url': 'https://github.com/dolphin-emu/dolphin.git', 'svn_url': 'https://github.com/dolphin-emu/dolphin', 'homepage': 'https://dolphin-emu.org', 'size': 558448, 'stargazers_count': 15272, 'watchers_count': 15272, 'language': 'C++', 'has_issues': False, 'has_projects': False, 'has_downloads': True, 'has_wiki': True, 'has_pages': False, 'has_discussions': False, 'forks_count': 3162, 'mirror_url': None, 'archived': False, 'disabled': False, 'open_issues_count': 446, 'license': {'key': 'other', 'name': 'Other', 'spdx_id': 'NOASSERTION', 'url': None, 'node_id': 'MDc6TGljZW5zZTA='}, 'allow_forking': True, 'is_template': False, 'web_commit_signoff_required': False, 'has_pull_requests': True, 'pull_request_creation_policy': 'all', 'topics': ['cpp', 'emulation', 'emulator', 'gamecube', 'wii'], 'visibility': 'public', 'forks': 3162, 'open_issues': 446, 'watchers': 15272, 'default_branch': 'master', 'allow_squash_merge': False, 'allow_merge_commit': True, 'allow_rebase_merge': False, 'allow_auto_merge': False, 'delete_branch_on_merge': False, 'allow_update_branch': False, 'use_squash_pr_title_as_default': False, 'squash_merge_commit_message': 'COMMIT_MESSAGES', 'squash_merge_commit_title': 'COMMIT_OR_PR_TITLE', 'merge_commit_message': 'PR_TITLE', 'merge_commit_title': 'MERGE_MESSAGE'}}, '_links': {'self': {'href': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/14731'}, 'html': {'href': 'https://github.com/dolphin-emu/dolphin/pull/14731'}, 'issue': {'href': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/14731'}, 'comments': {'href': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/14731/comments'}, 'review_comments': {'href': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/14731/comments'}, 'review_comment': {'href': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/comments{/number}'}, 'commits': {'href': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/14731/commits'}, 'statuses': {'href': 'https://api.github.com/repos/dolphin-emu/dolphin/statuses/24b41d58df2315831b74f76b95417f2739d02f9d'}}, 'author_association': 'NONE', 'auto_merge': None, 'assignee': None, 'active_lock_reason': None}, 'repository': {'id': 11577304, 'node_id': 'MDEwOlJlcG9zaXRvcnkxMTU3NzMwNA==', 'name': 'dolphin', 'full_name': 'dolphin-emu/dolphin', 'private': False, 'owner': {'login': 'dolphin-emu', 'id': 5050316, 'node_id': 'MDEyOk9yZ2FuaXphdGlvbjUwNTAzMTY=', 'avatar_url': 'https://avatars.githubusercontent.com/u/5050316?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/dolphin-emu', 'html_url': 'https://github.com/dolphin-emu', 'followers_url': 'https://api.github.com/users/dolphin-emu/followers', 'following_url': 'https://api.github.com/users/dolphin-emu/following{/other_user}', 'gists_url': 'https://api.github.com/users/dolphin-emu/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/dolphin-emu/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/dolphin-emu/subscriptions', 'organizations_url': 'https://api.github.com/users/dolphin-emu/orgs', 'repos_url': 'https://api.github.com/users/dolphin-emu/repos', 'events_url': 'https://api.github.com/users/dolphin-emu/events{/privacy}', 'received_events_url': 'https://api.github.com/users/dolphin-emu/received_events', 'type': 'Organization', 'user_view_type': 'public', 'site_admin': False}, 'html_url': 'https://github.com/dolphin-emu/dolphin', 'description': 'Dolphin is a GameCube / Wii emulator, allowing you to play games for these two platforms on PC with improvements.', 'fork': False, 'url': 'https://api.github.com/repos/dolphin-emu/dolphin', 'forks_url': 'https://api.github.com/repos/dolphin-emu/dolphin/forks', 'keys_url': 'https://api.github.com/repos/dolphin-emu/dolphin/keys{/key_id}', 'collaborators_url': 'https://api.github.com/repos/dolphin-emu/dolphin/collaborators{/collaborator}', 'teams_url': 'https://api.github.com/repos/dolphin-emu/dolphin/teams', 'hooks_url': 'https://api.github.com/repos/dolphin-emu/dolphin/hooks', 'issue_events_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/events{/number}', 'events_url': 'https://api.github.com/repos/dolphin-emu/dolphin/events', 'assignees_url': 'https://api.github.com/repos/dolphin-emu/dolphin/assignees{/user}', 'branches_url': 'https://api.github.com/repos/dolphin-emu/dolphin/branches{/branch}', 'tags_url': 'https://api.github.com/repos/dolphin-emu/dolphin/tags', 'blobs_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/blobs{/sha}', 'git_tags_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/tags{/sha}', 'git_refs_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/refs{/sha}', 'trees_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/trees{/sha}', 'statuses_url': 'https://api.github.com/repos/dolphin-emu/dolphin/statuses/{sha}', 'languages_url': 'https://api.github.com/repos/dolphin-emu/dolphin/languages', 'stargazers_url': 'https://api.github.com/repos/dolphin-emu/dolphin/stargazers', 'contributors_url': 'https://api.github.com/repos/dolphin-emu/dolphin/contributors', 'subscribers_url': 'https://api.github.com/repos/dolphin-emu/dolphin/subscribers', 'subscription_url': 'https://api.github.com/repos/dolphin-emu/dolphin/subscription', 'commits_url': 'https://api.github.com/repos/dolphin-emu/dolphin/commits{/sha}', 'git_commits_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/commits{/sha}', 'comments_url': 'https://api.github.com/repos/dolphin-emu/dolphin/comments{/number}', 'issue_comment_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/comments{/number}', 'contents_url': 'https://api.github.com/repos/dolphin-emu/dolphin/contents/{+path}', 'compare_url': 'https://api.github.com/repos/dolphin-emu/dolphin/compare/{base}...{head}', 'merges_url': 'https://api.github.com/repos/dolphin-emu/dolphin/merges', 'archive_url': 'https://api.github.com/repos/dolphin-emu/dolphin/{archive_format}{/ref}', 'downloads_url': 'https://api.github.com/repos/dolphin-emu/dolphin/downloads', 'issues_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues{/number}', 'pulls_url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls{/number}', 'milestones_url': 'https://api.github.com/repos/dolphin-emu/dolphin/milestones{/number}', 'notifications_url': 'https://api.github.com/repos/dolphin-emu/dolphin/notifications{?since,all,participating}', 'labels_url': 'https://api.github.com/repos/dolphin-emu/dolphin/labels{/name}', 'releases_url': 'https://api.github.com/repos/dolphin-emu/dolphin/releases{/id}', 'deployments_url': 'https://api.github.com/repos/dolphin-emu/dolphin/deployments', 'created_at': '2013-07-22T09:07:57Z', 'updated_at': '2026-07-18T18:44:16Z', 'pushed_at': '2026-07-18T10:34:54Z', 'git_url': 'git://github.com/dolphin-emu/dolphin.git', 'ssh_url': 'git@github.com:dolphin-emu/dolphin.git', 'clone_url': 'https://github.com/dolphin-emu/dolphin.git', 'svn_url': 'https://github.com/dolphin-emu/dolphin', 'homepage': 'https://dolphin-emu.org', 'size': 558448, 'stargazers_count': 15272, 'watchers_count': 15272, 'language': 'C++', 'has_issues': False, 'has_projects': False, 'has_downloads': True, 'has_wiki': True, 'has_pages': False, 'has_discussions': False, 'forks_count': 3162, 'mirror_url': None, 'archived': False, 'disabled': False, 'open_issues_count': 446, 'license': {'key': 'other', 'name': 'Other', 'spdx_id': 'NOASSERTION', 'url': None, 'node_id': 'MDc6TGljZW5zZTA='}, 'allow_forking': True, 'is_template': False, 'web_commit_signoff_required': False, 'has_pull_requests': True, 'pull_request_creation_policy': 'all', 'topics': ['cpp', 'emulation', 'emulator', 'gamecube', 'wii'], 'visibility': 'public', 'forks': 3162, 'open_issues': 446, 'watchers': 15272, 'default_branch': 'master', 'custom_properties': {}}, 'organization': {'login': 'dolphin-emu', 'id': 5050316, 'node_id': 'MDEyOk9yZ2FuaXphdGlvbjUwNTAzMTY=', 'url': 'https://api.github.com/orgs/dolphin-emu', 'repos_url': 'https://api.github.com/orgs/dolphin-emu/repos', 'events_url': 'https://api.github.com/orgs/dolphin-emu/events', 'hooks_url': 'https://api.github.com/orgs/dolphin-emu/hooks', 'issues_url': 'https://api.github.com/orgs/dolphin-emu/issues', 'members_url': 'https://api.github.com/orgs/dolphin-emu/members{/member}', 'public_members_url': 'https://api.github.com/orgs/dolphin-emu/public_members{/member}', 'avatar_url': 'https://avatars.githubusercontent.com/u/5050316?v=4', 'description': ''}, 'sender': {'login': 'phire', 'id': 138484, 'node_id': 'MDQ6VXNlcjEzODQ4NA==', 'avatar_url': 'https://avatars.githubusercontent.com/u/138484?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/phire', 'html_url': 'https://github.com/phire', 'followers_url': 'https://api.github.com/users/phire/followers', 'following_url': 'https://api.github.com/users/phire/following{/other_user}', 'gists_url': 'https://api.github.com/users/phire/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/phire/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/phire/subscriptions', 'organizations_url': 'https://api.github.com/users/phire/orgs', 'repos_url': 'https://api.github.com/users/phire/repos', 'events_url': 'https://api.github.com/users/phire/events{/privacy}', 'received_events_url': 'https://api.github.com/users/phire/received_events', 'type': 'User', 'user_view_type': 'public', 'site_admin': False}, 'installation': {'id': 35437981, 'node_id': 'MDIzOkludGVncmF0aW9uSW5zdGFsbGF0aW9uMzU0Mzc5ODE='}}, 'type': 'raw_gh_hook'}
2026-07-18T22:26:25.587516	{'source': 'webserver', 'gh_type': 'pull_request_review_comment', 'raw': {'action': 'created', 'comment': {'url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/comments/3609251889', 'pull_request_review_id': 4729322283, 'id': 3609251889, 'node_id': 'PRRC_kwDOALCn2M7XINAx', 'diff_hunk': '@@ -186,7 +380,304 @@ std::unique_ptr<WbfsFileReader> WbfsFileReader::Create(File::DirectIOFile file,\n   if (!reader->IsGood())\n     reader.reset();\n \n+  if (reader && reader->m_has_nkit_header)\n+    reader->ReadPartitionInfo();\n+\n   return reader;\n }\n \n+// Converts any disc image to WBFS with an NKit v2 header for lossless round-trips.\n+// Strips disc-level junk and partition-level junk (encrypted sectors whose decrypted\n+// content is zero or LFG padding), records a junk bitmap for reconstruction.\n+// See: https://github.com/dolphin-emu/dolphin/pull/14731\n+bool ConvertToWBFS(BlobReader* infile, const std::string& infile_path,\n+                   const std::string& outfile_path, const CompressCB& callback)\n+{\n+  ASSERT(infile->GetDataSizeType() == DataSizeType::Accurate ||\n+         infile->GetDataSizeType() == DataSizeType::UpperBound);\n+\n+  File::DirectIOFile outfile(outfile_path, File::AccessMode::Write);\n+  if (!outfile.IsOpen())\n+  {\n+    PanicAlertFmtT(\n+        "Failed to open the output file \\"{0}\\".\\n"\n+        "Check that you have permissions to write the target folder and that the media can "\n+        "be written.",\n+        outfile_path);\n+    return false;\n+  }\n+\n+  const u64 disc_size = infile->GetDataSize();\n+\n+  // These match the values used by standard WBFS tools (wwt, WBFS Manager)\n+  static constexpr u8 hd_sector_shift = 9;\n+  static constexpr u8 wbfs_sector_shift = 21;\n+  static constexpr u64 hd_sector_size = 1ull << hd_sector_shift;\n+  static constexpr u64 wbfs_sector_size = 1ull << wbfs_sector_shift;\n+\n+  const u64 blocks_per_disc = (disc_size + wbfs_sector_size - 1) / wbfs_sector_size;\n+  const u64 disc_info_size =\n+      Common::AlignUp(WII_DISC_HEADER_SIZE + blocks_per_disc * sizeof(u16), hd_sector_size);\n+\n+  // Read disc header (first 256 bytes contain disc_id, disc_num, title, etc.)\n+  std::vector<u8> disc_header(WII_DISC_HEADER_SIZE, 0);\n+  if (!infile->Read(0, WII_DISC_HEADER_SIZE, disc_header.data()))\n+  {\n+    PanicAlertFmtT("Failed to read from the input file \\"{0}\\".", infile_path);\n+    return false;\n+  }\n+\n+  // Use Volume for partition info and decrypted reads\n+  struct PartitionInfo\n+  {\n+    u64 data_offset;\n+    u64 data_size;\n+    Partition partition;\n+  };\n+  std::vector<PartitionInfo> partitions;\n+\n+  std::unique_ptr<VolumeDisc> volume = CreateDisc(infile_path);\n+  if (volume)\n+  {\n+    for (const Partition& partition : volume->GetPartitions())\n+    {\n+      const std::optional<u64> data_offset =\n+          volume->ReadSwappedAndShifted(partition.offset + 0x2B8, PARTITION_NONE);\n+      const std::optional<u64> data_size =\n+          volume->ReadSwappedAndShifted(partition.offset + 0x2BC, PARTITION_NONE);\n+      if (!data_offset || !data_size)\n+        continue;\n+\n+      PartitionInfo info;\n+      info.data_offset = partition.offset + *data_offset;\n+      info.data_size = *data_size;\n+      info.partition = partition;\n+      partitions.push_back(info);\n+    }\n+  }\n+\n+  // NKit v2 gap type bitmap: 1 bit per block, MSB-first, always sized for dual-layer\n+  const u64 gap_type_blocks = (DL_DVD_SIZE + wbfs_sector_size - 1) / wbfs_sector_size;\n+  const u64 gap_type_bytes = (gap_type_blocks + 7) / 8;\n+  std::vector<u8> gap_type(gap_type_bytes, 0);\n+\n+  // Compute data_start up front so we can write sectors during the scan\n+  const u64 data_start = Common::AlignUp(hd_sector_size + disc_info_size, wbfs_sector_size);\n+  const u16 wlba_base = static_cast<u16>(data_start / wbfs_sector_size);\n+\n+  // Single pass: scan, classify, hash, and write used sectors in one loop\n+  std::vector<u8> sector_buf(wbfs_sector_size, 0);\n+  std::vector<u16> wlba_table(blocks_per_disc, 0);\n+  u16 used_count = 0;\n+\n+  // NKit v2 stores four hash digests for verification\n+  auto sha1_ctx = Common::SHA1::CreateContext();\n+  u32 crc = Common::StartCRC32();\n+  mbedtls_md5_context md5_ctx{};\n+  mbedtls_md5_init(&md5_ctx);\n+  mbedtls_md5_starts_ret(&md5_ctx);\n+  XXH64_state_t* xxh_state = XXH64_createState();\n+  XXH64_reset(xxh_state, 0);\n+\n+  for (u64 i = 0; i < blocks_per_disc; i++)\n+  {\n+    if (i % 100 == 0)\n+    {\n+      const bool was_cancelled =\n+          !callback(Common::GetStringT("Converting"),\n+                    static_cast<float>(i) / static_cast<float>(blocks_per_disc));\n+      if (was_cancelled)\n+      {\n+        XXH64_freeState(xxh_state);\n+        mbedtls_md5_free(&md5_ctx);\n+        outfile.Close();\n+        File::Delete(outfile_path);\n+        return false;\n+      }\n+    }\n+\n+    const u64 offset = i * wbfs_sector_size;\n+    const size_t sz = static_cast<size_t>(std::min(wbfs_sector_size, disc_size - offset));\n+\n+    if (!infile->Read(offset, sz, sector_buf.data()))', 'path': 'Source/Core/DiscIO/WbfsBlob.cpp', 'commit_id': '24b41d58df2315831b74f76b95417f2739d02f9d', 'original_commit_id': '24b41d58df2315831b74f76b95417f2739d02f9d', 'user': {'login': 'phire', 'id': 138484, 'node_id': 'MDQ6VXNlcjEzODQ4NA==', 'avatar_url': 'https://avatars.githubusercontent.com/u/138484?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/phire', 'html_url': 'https://github.com/phire', 'followers_url': 'https://api.github.com/users/phire/followers', 'following_url': 'https://api.github.com/users/phire/following{/other_user}', 'gists_url': 'https://api.github.com/users/phire/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/phire/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/phire/subscriptions', 'organizations_url': 'https://api.github.com/users/phire/orgs', 'repos_url': 'https://api.github.com/users/phire/repos', 'events_url': 'https://api.github.com/users/phire/events{/privacy}', 'received_events_url': 'https://api.github.com/users/phire/received_events', 'type': 'User', 'user_view_type': 'public', 'site_admin': False}, 'body': "Don't read here. \nIf the sector is in a partition and is either junk or zeros, there is no need to fetch the encrypted version. That's just going to trigger an unnecessary encrypt operation for RVZ/WIA inputs.\n\nOnce we discover the sector is outside a partition, or contains data, then we can read/encrypt it. ", 'created_at': '2026-07-18T21:46:22Z', 'updated_at': '2026-07-18T22:26:23Z', 'html_url': 'https://github.com/dolphin-emu/dolphin/pull/14731#discussion_r3609251889', 'pull_request_url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/14731', '_links': {'self': {'href': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/comments/3609251889'}, 'html': {'href': 'https://github.com/dolphin-emu/dolphin/pull/14731#discussion_r3609251889'}, 'pull_request': {'href': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/14731'}}, 'reactions': {'url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/comments/3609251889/reactions', 'total_count': 0, '+1': 0, '-1': 0, 'laugh': 0, 'hooray': 0, 'confused': 0, 'heart': 0, 'rocket': 0, 'eyes': 0}, 'start_line': None, 'original_start_line': None, 'start_side': None, 'line': 502, 'original_line': 502, 'side': 'RIGHT', 'author_association': 'MEMBER', 'original_position': 409, 'position': 409, 'subject_type': 'line'}, 'pull_request': {'url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/14731', 'id': 4056977334, 'node_id': 'PR_kwDOALCn2M7x0I-2', 'html_url': 'https://github.com/dolphin-emu/dolphin/pull/14731', 'diff_url': 'https://github.com/dolphin-emu/dolphin/pull/14731.diff', 'patch_url': 'https://github.com/dolphin-emu/dolphin/pull/14731.patch', 'issue_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/14731', 'number': 14731, 'state': 'open', 'locked': False, 'title': 'Convert To WBFS Support', 'user': {'login': 'thethiny', 'id': 6018214, 'node_id': 'MDQ6VXNlcjYwMTgyMTQ=', 'avatar_url': 'https://avatars.githubusercontent.com/u/6018214?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/thethiny', 'html_url': 'https://github.com/thethiny', 'followers_url': 'https://api.github.com/users/thethiny/followers', 'following_url': 'https://api.github.com/users/thethiny/following{/other_user}', 'gists_url': 'https://api.github.com/users/thethiny/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/thethiny/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/thethiny/subscriptions', 'organizations_url': 'https://api.github.com/users/thethiny/orgs', 'repos_url': 'https://api.github.com/users/thethiny/repos', 'events_url': 'https://api.github.com/users/thethiny/events{/privacy}', 'received_events_url': 'https://api.github.com/users/thethiny/received_events', 'type': 'User', 'user_view_type': 'public', 'site_admin': False}, 'body': "This PR introduces Conversion **to** WBFS support. WBFS is the format that is used by USB Loaders on a real Wii device.\r\n\r\n## Design decisions & hardcoded values\r\nThe writer uses fixed sector sizes that match what [libwbfs (the reference implementation by kwiirk)](https://github.com/kwiirk/wbfs/blob/master/libwbfs/libwbfs.c#L128-L134) computes for a standard single-layer Wii disc. These 2 hardcodes are stable and work correctly across all my testings.\r\n- HD sector shift: 9 (512 bytes)\r\n- WBFS sector shift: 21 (2 MiB)\r\nThese are not configurable via the UI. All existing WBFS tools use these values, and since the aim is to support USB Loaders then this has been tested and it is working on a real Wii.\r\n\r\nConverting from WBFS is not enabled. The existing `WbfsFileReader` reports `DataSizeType::UpperBound`, and `ShouldAllowConversion()` requires `Accurate`. I am able to support this but since it was hardcoded by the Dolphin team I thought a discussion is warranted.\r\n\r\n## Testing\r\n- Verified with DolphinTool header and DolphinTool verify\r\n- Verified with wit FILETYPE and wit DUMP (Wiimm's ISO Tools recognizes valid WBFS structure, partitions, encryption)\r\n- Tested ISO to WBFS and RVZ to WBFS conversions\r\n- Output file sizes match Wii Backup Manager when scrubbing is enabled (~0.1% difference), works when scrubbing is disabled.\r\n- Output WBFS files play correctly in Dolphin\r\n- Output WBFS files play correctly on a real Wii using USB Loader GX e25c4f3\r\n", 'created_at': '2026-07-15T01:16:25Z', 'updated_at': '2026-07-18T22:16:59Z', 'closed_at': None, 'merged_at': None, 'merge_commit_sha': '228f93416dd80eb09da834ad7852c8eaa4d9212b', 'assignees': [], 'requested_reviewers': [], 'requested_teams': [], 'labels': [], 'milestone': None, 'draft': False, 'commits_url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/14731/commits', 'review_comments_url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/14731/comments', 'review_comment_url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/comments{/number}', 'comments_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/14731/comments', 'statuses_url': 'https://api.github.com/repos/dolphin-emu/dolphin/statuses/24b41d58df2315831b74f76b95417f2739d02f9d', 'head': {'label': 'thethiny:wbfs-conversion', 'ref': 'wbfs-conversion', 'sha': '24b41d58df2315831b74f76b95417f2739d02f9d', 'user': {'login': 'thethiny', 'id': 6018214, 'node_id': 'MDQ6VXNlcjYwMTgyMTQ=', 'avatar_url': 'https://avatars.githubusercontent.com/u/6018214?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/thethiny', 'html_url': 'https://github.com/thethiny', 'followers_url': 'https://api.github.com/users/thethiny/followers', 'following_url': 'https://api.github.com/users/thethiny/following{/other_user}', 'gists_url': 'https://api.github.com/users/thethiny/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/thethiny/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/thethiny/subscriptions', 'organizations_url': 'https://api.github.com/users/thethiny/orgs', 'repos_url': 'https://api.github.com/users/thethiny/repos', 'events_url': 'https://api.github.com/users/thethiny/events{/privacy}', 'received_events_url': 'https://api.github.com/users/thethiny/received_events', 'type': 'User', 'user_view_type': 'public', 'site_admin': False}, 'repo': {'id': 1298654395, 'node_id': 'R_kgDOTWfkuw', 'name': 'dolphin', 'full_name': 'thethiny/dolphin', 'private': False, 'owner': {'login': 'thethiny', 'id': 6018214, 'node_id': 'MDQ6VXNlcjYwMTgyMTQ=', 'avatar_url': 'https://avatars.githubusercontent.com/u/6018214?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/thethiny', 'html_url': 'https://github.com/thethiny', 'followers_url': 'https://api.github.com/users/thethiny/followers', 'following_url': 'https://api.github.com/users/thethiny/following{/other_user}', 'gists_url': 'https://api.github.com/users/thethiny/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/thethiny/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/thethiny/subscriptions', 'organizations_url': 'https://api.github.com/users/thethiny/orgs', 'repos_url': 'https://api.github.com/users/thethiny/repos', 'events_url': 'https://api.github.com/users/thethiny/events{/privacy}', 'received_events_url': 'https://api.github.com/users/thethiny/received_events', 'type': 'User', 'user_view_type': 'public', 'site_admin': False}, 'html_url': 'https://github.com/thethiny/dolphin', 'description': 'Dolphin is a GameCube / Wii emulator, allowing you to play games for these two platforms on PC with improvements.', 'fork': True, 'url': 'https://api.github.com/repos/thethiny/dolphin', 'forks_url': 'https://api.github.com/repos/thethiny/dolphin/forks', 'keys_url': 'https://api.github.com/repos/thethiny/dolphin/keys{/key_id}', 'collaborators_url': 'https://api.github.com/repos/thethiny/dolphin/collaborators{/collaborator}', 'teams_url': 'https://api.github.com/repos/thethiny/dolphin/teams', 'hooks_url': 'https://api.github.com/repos/thethiny/dolphin/hooks', 'issue_events_url': 'https://api.github.com/repos/thethiny/dolphin/issues/events{/number}', 'events_url': 'https://api.github.com/repos/thethiny/dolphin/events', 'assignees_url': 'https://api.github.com/repos/thethiny/dolphin/assignees{/user}', 'branches_url': 'https://api.github.com/repos/thethiny/dolphin/branches{/branch}', 'tags_url': 'https://api.github.com/repos/thethiny/dolphin/tags', 'blobs_url': 'https://api.github.com/repos/thethiny/dolphin/git/blobs{/sha}', 'git_tags_url': 'https://api.github.com/repos/thethiny/dolphin/git/tags{/sha}', 'git_refs_url': 'https://api.github.com/repos/thethiny/dolphin/git/refs{/sha}', 'trees_url': 'https://api.github.com/repos/thethiny/dolphin/git/trees{/sha}', 'statuses_url': 'https://api.github.com/repos/thethiny/dolphin/statuses/{sha}', 'languages_url': 'https://api.github.com/repos/thethiny/dolphin/languages', 'stargazers_url': 'https://api.github.com/repos/thethiny/dolphin/stargazers', 'contributors_url': 'https://api.github.com/repos/thethiny/dolphin/contributors', 'subscribers_url': 'https://api.github.com/repos/thethiny/dolphin/subscribers', 'subscription_url': 'https://api.github.com/repos/thethiny/dolphin/subscription', 'commits_url': 'https://api.github.com/repos/thethiny/dolphin/commits{/sha}', 'git_commits_url': 'https://api.github.com/repos/thethiny/dolphin/git/commits{/sha}', 'comments_url': 'https://api.github.com/repos/thethiny/dolphin/comments{/number}', 'issue_comment_url': 'https://api.github.com/repos/thethiny/dolphin/issues/comments{/number}', 'contents_url': 'https://api.github.com/repos/thethiny/dolphin/contents/{+path}', 'compare_url': 'https://api.github.com/repos/thethiny/dolphin/compare/{base}...{head}', 'merges_url': 'https://api.github.com/repos/thethiny/dolphin/merges', 'archive_url': 'https://api.github.com/repos/thethiny/dolphin/{archive_format}{/ref}', 'downloads_url': 'https://api.github.com/repos/thethiny/dolphin/downloads', 'issues_url': 'https://api.github.com/repos/thethiny/dolphin/issues{/number}', 'pulls_url': 'https://api.github.com/repos/thethiny/dolphin/pulls{/number}', 'milestones_url': 'https://api.github.com/repos/thethiny/dolphin/milestones{/number}', 'notifications_url': 'https://api.github.com/repos/thethiny/dolphin/notifications{?since,all,participating}', 'labels_url': 'https://api.github.com/repos/thethiny/dolphin/labels{/name}', 'releases_url': 'https://api.github.com/repos/thethiny/dolphin/releases{/id}', 'deployments_url': 'https://api.github.com/repos/thethiny/dolphin/deployments', 'created_at': '2026-07-12T22:09:13Z', 'updated_at': '2026-07-12T22:09:13Z', 'pushed_at': '2026-07-18T20:35:03Z', 'git_url': 'git://github.com/thethiny/dolphin.git', 'ssh_url': 'git@github.com:thethiny/dolphin.git', 'clone_url': 'https://github.com/thethiny/dolphin.git', 'svn_url': 'https://github.com/thethiny/dolphin', 'homepage': 'https://dolphin-emu.org', 'size': 515471, 'stargazers_count': 0, 'watchers_count': 0, 'language': None, 'has_issues': False, 'has_projects': True, 'has_downloads': True, 'has_wiki': True, 'has_pages': False, 'has_discussions': False, 'forks_count': 0, 'mirror_url': None, 'archived': False, 'disabled': False, 'open_issues_count': 0, 'license': {'key': 'other', 'name': 'Other', 'spdx_id': 'NOASSERTION', 'url': None, 'node_id': 'MDc6TGljZW5zZTA='}, 'allow_forking': True, 'is_template': False, 'web_commit_signoff_required': False, 'has_pull_requests': True, 'pull_request_creation_policy': 'all', 'topics': [], 'visibility': 'public', 'forks': 0, 'open_issues': 0, 'watchers': 0, 'default_branch': 'master', 'allow_squash_merge': True, 'allow_merge_commit': True, 'allow_rebase_merge': True, 'allow_auto_merge': False, 'delete_branch_on_merge': False, 'allow_update_branch': False, 'use_squash_pr_title_as_default': False, 'squash_merge_commit_message': 'COMMIT_MESSAGES', 'squash_merge_commit_title': 'COMMIT_OR_PR_TITLE', 'merge_commit_message': 'PR_TITLE', 'merge_commit_title': 'MERGE_MESSAGE'}}, 'base': {'label': 'dolphin-emu:master', 'ref': 'master', 'sha': 'd3b2943807dd0073f7767947466dd73cccfef319', 'user': {'login': 'dolphin-emu', 'id': 5050316, 'node_id': 'MDEyOk9yZ2FuaXphdGlvbjUwNTAzMTY=', 'avatar_url': 'https://avatars.githubusercontent.com/u/5050316?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/dolphin-emu', 'html_url': 'https://github.com/dolphin-emu', 'followers_url': 'https://api.github.com/users/dolphin-emu/followers', 'following_url': 'https://api.github.com/users/dolphin-emu/following{/other_user}', 'gists_url': 'https://api.github.com/users/dolphin-emu/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/dolphin-emu/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/dolphin-emu/subscriptions', 'organizations_url': 'https://api.github.com/users/dolphin-emu/orgs', 'repos_url': 'https://api.github.com/users/dolphin-emu/repos', 'events_url': 'https://api.github.com/users/dolphin-emu/events{/privacy}', 'received_events_url': 'https://api.github.com/users/dolphin-emu/received_events', 'type': 'Organization', 'user_view_type': 'public', 'site_admin': False}, 'repo': {'id': 11577304, 'node_id': 'MDEwOlJlcG9zaXRvcnkxMTU3NzMwNA==', 'name': 'dolphin', 'full_name': 'dolphin-emu/dolphin', 'private': False, 'owner': {'login': 'dolphin-emu', 'id': 5050316, 'node_id': 'MDEyOk9yZ2FuaXphdGlvbjUwNTAzMTY=', 'avatar_url': 'https://avatars.githubusercontent.com/u/5050316?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/dolphin-emu', 'html_url': 'https://github.com/dolphin-emu', 'followers_url': 'https://api.github.com/users/dolphin-emu/followers', 'following_url': 'https://api.github.com/users/dolphin-emu/following{/other_user}', 'gists_url': 'https://api.github.com/users/dolphin-emu/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/dolphin-emu/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/dolphin-emu/subscriptions', 'organizations_url': 'https://api.github.com/users/dolphin-emu/orgs', 'repos_url': 'https://api.github.com/users/dolphin-emu/repos', 'events_url': 'https://api.github.com/users/dolphin-emu/events{/privacy}', 'received_events_url': 'https://api.github.com/users/dolphin-emu/received_events', 'type': 'Organization', 'user_view_type': 'public', 'site_admin': False}, 'html_url': 'https://github.com/dolphin-emu/dolphin', 'description': 'Dolphin is a GameCube / Wii emulator, allowing you to play games for these two platforms on PC with improvements.', 'fork': False, 'url': 'https://api.github.com/repos/dolphin-emu/dolphin', 'forks_url': 'https://api.github.com/repos/dolphin-emu/dolphin/forks', 'keys_url': 'https://api.github.com/repos/dolphin-emu/dolphin/keys{/key_id}', 'collaborators_url': 'https://api.github.com/repos/dolphin-emu/dolphin/collaborators{/collaborator}', 'teams_url': 'https://api.github.com/repos/dolphin-emu/dolphin/teams', 'hooks_url': 'https://api.github.com/repos/dolphin-emu/dolphin/hooks', 'issue_events_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/events{/number}', 'events_url': 'https://api.github.com/repos/dolphin-emu/dolphin/events', 'assignees_url': 'https://api.github.com/repos/dolphin-emu/dolphin/assignees{/user}', 'branches_url': 'https://api.github.com/repos/dolphin-emu/dolphin/branches{/branch}', 'tags_url': 'https://api.github.com/repos/dolphin-emu/dolphin/tags', 'blobs_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/blobs{/sha}', 'git_tags_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/tags{/sha}', 'git_refs_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/refs{/sha}', 'trees_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/trees{/sha}', 'statuses_url': 'https://api.github.com/repos/dolphin-emu/dolphin/statuses/{sha}', 'languages_url': 'https://api.github.com/repos/dolphin-emu/dolphin/languages', 'stargazers_url': 'https://api.github.com/repos/dolphin-emu/dolphin/stargazers', 'contributors_url': 'https://api.github.com/repos/dolphin-emu/dolphin/contributors', 'subscribers_url': 'https://api.github.com/repos/dolphin-emu/dolphin/subscribers', 'subscription_url': 'https://api.github.com/repos/dolphin-emu/dolphin/subscription', 'commits_url': 'https://api.github.com/repos/dolphin-emu/dolphin/commits{/sha}', 'git_commits_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/commits{/sha}', 'comments_url': 'https://api.github.com/repos/dolphin-emu/dolphin/comments{/number}', 'issue_comment_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/comments{/number}', 'contents_url': 'https://api.github.com/repos/dolphin-emu/dolphin/contents/{+path}', 'compare_url': 'https://api.github.com/repos/dolphin-emu/dolphin/compare/{base}...{head}', 'merges_url': 'https://api.github.com/repos/dolphin-emu/dolphin/merges', 'archive_url': 'https://api.github.com/repos/dolphin-emu/dolphin/{archive_format}{/ref}', 'downloads_url': 'https://api.github.com/repos/dolphin-emu/dolphin/downloads', 'issues_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues{/number}', 'pulls_url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls{/number}', 'milestones_url': 'https://api.github.com/repos/dolphin-emu/dolphin/milestones{/number}', 'notifications_url': 'https://api.github.com/repos/dolphin-emu/dolphin/notifications{?since,all,participating}', 'labels_url': 'https://api.github.com/repos/dolphin-emu/dolphin/labels{/name}', 'releases_url': 'https://api.github.com/repos/dolphin-emu/dolphin/releases{/id}', 'deployments_url': 'https://api.github.com/repos/dolphin-emu/dolphin/deployments', 'created_at': '2013-07-22T09:07:57Z', 'updated_at': '2026-07-18T18:44:16Z', 'pushed_at': '2026-07-18T10:34:54Z', 'git_url': 'git://github.com/dolphin-emu/dolphin.git', 'ssh_url': 'git@github.com:dolphin-emu/dolphin.git', 'clone_url': 'https://github.com/dolphin-emu/dolphin.git', 'svn_url': 'https://github.com/dolphin-emu/dolphin', 'homepage': 'https://dolphin-emu.org', 'size': 558448, 'stargazers_count': 15272, 'watchers_count': 15272, 'language': 'C++', 'has_issues': False, 'has_projects': False, 'has_downloads': True, 'has_wiki': True, 'has_pages': False, 'has_discussions': False, 'forks_count': 3162, 'mirror_url': None, 'archived': False, 'disabled': False, 'open_issues_count': 446, 'license': {'key': 'other', 'name': 'Other', 'spdx_id': 'NOASSERTION', 'url': None, 'node_id': 'MDc6TGljZW5zZTA='}, 'allow_forking': True, 'is_template': False, 'web_commit_signoff_required': False, 'has_pull_requests': True, 'pull_request_creation_policy': 'all', 'topics': ['cpp', 'emulation', 'emulator', 'gamecube', 'wii'], 'visibility': 'public', 'forks': 3162, 'open_issues': 446, 'watchers': 15272, 'default_branch': 'master', 'allow_squash_merge': False, 'allow_merge_commit': True, 'allow_rebase_merge': False, 'allow_auto_merge': False, 'delete_branch_on_merge': False, 'allow_update_branch': False, 'use_squash_pr_title_as_default': False, 'squash_merge_commit_message': 'COMMIT_MESSAGES', 'squash_merge_commit_title': 'COMMIT_OR_PR_TITLE', 'merge_commit_message': 'PR_TITLE', 'merge_commit_title': 'MERGE_MESSAGE'}}, '_links': {'self': {'href': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/14731'}, 'html': {'href': 'https://github.com/dolphin-emu/dolphin/pull/14731'}, 'issue': {'href': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/14731'}, 'comments': {'href': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/14731/comments'}, 'review_comments': {'href': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/14731/comments'}, 'review_comment': {'href': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/comments{/number}'}, 'commits': {'href': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/14731/commits'}, 'statuses': {'href': 'https://api.github.com/repos/dolphin-emu/dolphin/statuses/24b41d58df2315831b74f76b95417f2739d02f9d'}}, 'author_association': 'NONE', 'auto_merge': None, 'assignee': None, 'active_lock_reason': None}, 'repository': {'id': 11577304, 'node_id': 'MDEwOlJlcG9zaXRvcnkxMTU3NzMwNA==', 'name': 'dolphin', 'full_name': 'dolphin-emu/dolphin', 'private': False, 'owner': {'login': 'dolphin-emu', 'id': 5050316, 'node_id': 'MDEyOk9yZ2FuaXphdGlvbjUwNTAzMTY=', 'avatar_url': 'https://avatars.githubusercontent.com/u/5050316?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/dolphin-emu', 'html_url': 'https://github.com/dolphin-emu', 'followers_url': 'https://api.github.com/users/dolphin-emu/followers', 'following_url': 'https://api.github.com/users/dolphin-emu/following{/other_user}', 'gists_url': 'https://api.github.com/users/dolphin-emu/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/dolphin-emu/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/dolphin-emu/subscriptions', 'organizations_url': 'https://api.github.com/users/dolphin-emu/orgs', 'repos_url': 'https://api.github.com/users/dolphin-emu/repos', 'events_url': 'https://api.github.com/users/dolphin-emu/events{/privacy}', 'received_events_url': 'https://api.github.com/users/dolphin-emu/received_events', 'type': 'Organization', 'user_view_type': 'public', 'site_admin': False}, 'html_url': 'https://github.com/dolphin-emu/dolphin', 'description': 'Dolphin is a GameCube / Wii emulator, allowing you to play games for these two platforms on PC with improvements.', 'fork': False, 'url': 'https://api.github.com/repos/dolphin-emu/dolphin', 'forks_url': 'https://api.github.com/repos/dolphin-emu/dolphin/forks', 'keys_url': 'https://api.github.com/repos/dolphin-emu/dolphin/keys{/key_id}', 'collaborators_url': 'https://api.github.com/repos/dolphin-emu/dolphin/collaborators{/collaborator}', 'teams_url': 'https://api.github.com/repos/dolphin-emu/dolphin/teams', 'hooks_url': 'https://api.github.com/repos/dolphin-emu/dolphin/hooks', 'issue_events_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/events{/number}', 'events_url': 'https://api.github.com/repos/dolphin-emu/dolphin/events', 'assignees_url': 'https://api.github.com/repos/dolphin-emu/dolphin/assignees{/user}', 'branches_url': 'https://api.github.com/repos/dolphin-emu/dolphin/branches{/branch}', 'tags_url': 'https://api.github.com/repos/dolphin-emu/dolphin/tags', 'blobs_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/blobs{/sha}', 'git_tags_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/tags{/sha}', 'git_refs_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/refs{/sha}', 'trees_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/trees{/sha}', 'statuses_url': 'https://api.github.com/repos/dolphin-emu/dolphin/statuses/{sha}', 'languages_url': 'https://api.github.com/repos/dolphin-emu/dolphin/languages', 'stargazers_url': 'https://api.github.com/repos/dolphin-emu/dolphin/stargazers', 'contributors_url': 'https://api.github.com/repos/dolphin-emu/dolphin/contributors', 'subscribers_url': 'https://api.github.com/repos/dolphin-emu/dolphin/subscribers', 'subscription_url': 'https://api.github.com/repos/dolphin-emu/dolphin/subscription', 'commits_url': 'https://api.github.com/repos/dolphin-emu/dolphin/commits{/sha}', 'git_commits_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/commits{/sha}', 'comments_url': 'https://api.github.com/repos/dolphin-emu/dolphin/comments{/number}', 'issue_comment_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/comments{/number}', 'contents_url': 'https://api.github.com/repos/dolphin-emu/dolphin/contents/{+path}', 'compare_url': 'https://api.github.com/repos/dolphin-emu/dolphin/compare/{base}...{head}', 'merges_url': 'https://api.github.com/repos/dolphin-emu/dolphin/merges', 'archive_url': 'https://api.github.com/repos/dolphin-emu/dolphin/{archive_format}{/ref}', 'downloads_url': 'https://api.github.com/repos/dolphin-emu/dolphin/downloads', 'issues_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues{/number}', 'pulls_url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls{/number}', 'milestones_url': 'https://api.github.com/repos/dolphin-emu/dolphin/milestones{/number}', 'notifications_url': 'https://api.github.com/repos/dolphin-emu/dolphin/notifications{?since,all,participating}', 'labels_url': 'https://api.github.com/repos/dolphin-emu/dolphin/labels{/name}', 'releases_url': 'https://api.github.com/repos/dolphin-emu/dolphin/releases{/id}', 'deployments_url': 'https://api.github.com/repos/dolphin-emu/dolphin/deployments', 'created_at': '2013-07-22T09:07:57Z', 'updated_at': '2026-07-18T18:44:16Z', 'pushed_at': '2026-07-18T10:34:54Z', 'git_url': 'git://github.com/dolphin-emu/dolphin.git', 'ssh_url': 'git@github.com:dolphin-emu/dolphin.git', 'clone_url': 'https://github.com/dolphin-emu/dolphin.git', 'svn_url': 'https://github.com/dolphin-emu/dolphin', 'homepage': 'https://dolphin-emu.org', 'size': 558448, 'stargazers_count': 15272, 'watchers_count': 15272, 'language': 'C++', 'has_issues': False, 'has_projects': False, 'has_downloads': True, 'has_wiki': True, 'has_pages': False, 'has_discussions': False, 'forks_count': 3162, 'mirror_url': None, 'archived': False, 'disabled': False, 'open_issues_count': 446, 'license': {'key': 'other', 'name': 'Other', 'spdx_id': 'NOASSERTION', 'url': None, 'node_id': 'MDc6TGljZW5zZTA='}, 'allow_forking': True, 'is_template': False, 'web_commit_signoff_required': False, 'has_pull_requests': True, 'pull_request_creation_policy': 'all', 'topics': ['cpp', 'emulation', 'emulator', 'gamecube', 'wii'], 'visibility': 'public', 'forks': 3162, 'open_issues': 446, 'watchers': 15272, 'default_branch': 'master', 'custom_properties': {}}, 'organization': {'login': 'dolphin-emu', 'id': 5050316, 'node_id': 'MDEyOk9yZ2FuaXphdGlvbjUwNTAzMTY=', 'url': 'https://api.github.com/orgs/dolphin-emu', 'repos_url': 'https://api.github.com/orgs/dolphin-emu/repos', 'events_url': 'https://api.github.com/orgs/dolphin-emu/events', 'hooks_url': 'https://api.github.com/orgs/dolphin-emu/hooks', 'issues_url': 'https://api.github.com/orgs/dolphin-emu/issues', 'members_url': 'https://api.github.com/orgs/dolphin-emu/members{/member}', 'public_members_url': 'https://api.github.com/orgs/dolphin-emu/public_members{/member}', 'avatar_url': 'https://avatars.githubusercontent.com/u/5050316?v=4', 'description': ''}, 'sender': {'login': 'phire', 'id': 138484, 'node_id': 'MDQ6VXNlcjEzODQ4NA==', 'avatar_url': 'https://avatars.githubusercontent.com/u/138484?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/phire', 'html_url': 'https://github.com/phire', 'followers_url': 'https://api.github.com/users/phire/followers', 'following_url': 'https://api.github.com/users/phire/following{/other_user}', 'gists_url': 'https://api.github.com/users/phire/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/phire/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/phire/subscriptions', 'organizations_url': 'https://api.github.com/users/phire/orgs', 'repos_url': 'https://api.github.com/users/phire/repos', 'events_url': 'https://api.github.com/users/phire/events{/privacy}', 'received_events_url': 'https://api.github.com/users/phire/received_events', 'type': 'User', 'user_view_type': 'public', 'site_admin': False}, 'installation': {'id': 35437981, 'node_id': 'MDIzOkludGVncmF0aW9uSW5zdGFsbGF0aW9uMzU0Mzc5ODE='}}, 'type': 'raw_gh_hook'}
2026-07-18T22:26:25.586929	{'source': 'webserver', 'gh_type': 'pull_request_review_comment', 'raw': {'action': 'created', 'comment': {'url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/comments/3609258421', 'pull_request_review_id': 4729322283, 'id': 3609258421, 'node_id': 'PRRC_kwDOALCn2M7XIOm1', 'diff_hunk': '@@ -186,7 +380,304 @@ std::unique_ptr<WbfsFileReader> WbfsFileReader::Create(File::DirectIOFile file,\n   if (!reader->IsGood())\n     reader.reset();\n \n+  if (reader && reader->m_has_nkit_header)\n+    reader->ReadPartitionInfo();\n+\n   return reader;\n }\n \n+// Converts any disc image to WBFS with an NKit v2 header for lossless round-trips.\n+// Strips disc-level junk and partition-level junk (encrypted sectors whose decrypted\n+// content is zero or LFG padding), records a junk bitmap for reconstruction.\n+// See: https://github.com/dolphin-emu/dolphin/pull/14731\n+bool ConvertToWBFS(BlobReader* infile, const std::string& infile_path,\n+                   const std::string& outfile_path, const CompressCB& callback)\n+{\n+  ASSERT(infile->GetDataSizeType() == DataSizeType::Accurate ||\n+         infile->GetDataSizeType() == DataSizeType::UpperBound);\n+\n+  File::DirectIOFile outfile(outfile_path, File::AccessMode::Write);\n+  if (!outfile.IsOpen())\n+  {\n+    PanicAlertFmtT(\n+        "Failed to open the output file \\"{0}\\".\\n"\n+        "Check that you have permissions to write the target folder and that the media can "\n+        "be written.",\n+        outfile_path);\n+    return false;\n+  }\n+\n+  const u64 disc_size = infile->GetDataSize();\n+\n+  // These match the values used by standard WBFS tools (wwt, WBFS Manager)\n+  static constexpr u8 hd_sector_shift = 9;\n+  static constexpr u8 wbfs_sector_shift = 21;\n+  static constexpr u64 hd_sector_size = 1ull << hd_sector_shift;\n+  static constexpr u64 wbfs_sector_size = 1ull << wbfs_sector_shift;\n+\n+  const u64 blocks_per_disc = (disc_size + wbfs_sector_size - 1) / wbfs_sector_size;\n+  const u64 disc_info_size =\n+      Common::AlignUp(WII_DISC_HEADER_SIZE + blocks_per_disc * sizeof(u16), hd_sector_size);\n+\n+  // Read disc header (first 256 bytes contain disc_id, disc_num, title, etc.)\n+  std::vector<u8> disc_header(WII_DISC_HEADER_SIZE, 0);\n+  if (!infile->Read(0, WII_DISC_HEADER_SIZE, disc_header.data()))\n+  {\n+    PanicAlertFmtT("Failed to read from the input file \\"{0}\\".", infile_path);\n+    return false;\n+  }\n+\n+  // Use Volume for partition info and decrypted reads\n+  struct PartitionInfo\n+  {\n+    u64 data_offset;\n+    u64 data_size;\n+    Partition partition;\n+  };\n+  std::vector<PartitionInfo> partitions;\n+\n+  std::unique_ptr<VolumeDisc> volume = CreateDisc(infile_path);\n+  if (volume)\n+  {\n+    for (const Partition& partition : volume->GetPartitions())\n+    {\n+      const std::optional<u64> data_offset =\n+          volume->ReadSwappedAndShifted(partition.offset + 0x2B8, PARTITION_NONE);\n+      const std::optional<u64> data_size =\n+          volume->ReadSwappedAndShifted(partition.offset + 0x2BC, PARTITION_NONE);\n+      if (!data_offset || !data_size)\n+        continue;\n+\n+      PartitionInfo info;\n+      info.data_offset = partition.offset + *data_offset;\n+      info.data_size = *data_size;\n+      info.partition = partition;\n+      partitions.push_back(info);\n+    }\n+  }\n+\n+  // NKit v2 gap type bitmap: 1 bit per block, MSB-first, always sized for dual-layer\n+  const u64 gap_type_blocks = (DL_DVD_SIZE + wbfs_sector_size - 1) / wbfs_sector_size;\n+  const u64 gap_type_bytes = (gap_type_blocks + 7) / 8;\n+  std::vector<u8> gap_type(gap_type_bytes, 0);\n+\n+  // Compute data_start up front so we can write sectors during the scan\n+  const u64 data_start = Common::AlignUp(hd_sector_size + disc_info_size, wbfs_sector_size);\n+  const u16 wlba_base = static_cast<u16>(data_start / wbfs_sector_size);\n+\n+  // Single pass: scan, classify, hash, and write used sectors in one loop\n+  std::vector<u8> sector_buf(wbfs_sector_size, 0);\n+  std::vector<u16> wlba_table(blocks_per_disc, 0);\n+  u16 used_count = 0;\n+\n+  // NKit v2 stores four hash digests for verification\n+  auto sha1_ctx = Common::SHA1::CreateContext();\n+  u32 crc = Common::StartCRC32();\n+  mbedtls_md5_context md5_ctx{};\n+  mbedtls_md5_init(&md5_ctx);\n+  mbedtls_md5_starts_ret(&md5_ctx);\n+  XXH64_state_t* xxh_state = XXH64_createState();\n+  XXH64_reset(xxh_state, 0);\n+\n+  for (u64 i = 0; i < blocks_per_disc; i++)\n+  {\n+    if (i % 100 == 0)\n+    {\n+      const bool was_cancelled =\n+          !callback(Common::GetStringT("Converting"),\n+                    static_cast<float>(i) / static_cast<float>(blocks_per_disc));\n+      if (was_cancelled)\n+      {\n+        XXH64_freeState(xxh_state);\n+        mbedtls_md5_free(&md5_ctx);\n+        outfile.Close();\n+        File::Delete(outfile_path);\n+        return false;\n+      }\n+    }\n+\n+    const u64 offset = i * wbfs_sector_size;\n+    const size_t sz = static_cast<size_t>(std::min(wbfs_sector_size, disc_size - offset));\n+\n+    if (!infile->Read(offset, sz, sector_buf.data()))\n+    {\n+      PanicAlertFmtT("Failed to read from the input file \\"{0}\\".", infile_path);\n+      XXH64_freeState(xxh_state);\n+      mbedtls_md5_free(&md5_ctx);\n+      outfile.Close();\n+      File::Delete(outfile_path);\n+      return false;\n+    }\n+\n+    // Update all four hashes with the full disc data\n+    sha1_ctx->Update(sector_buf.data(), sz);\n+    crc = Common::UpdateCRC32(crc, sector_buf.data(), sz);\n+    mbedtls_md5_update_ret(&md5_ctx, sector_buf.data(), sz);\n+    XXH64_update(xxh_state, sector_buf.data(), sz);\n+\n+    // Find which partition (if any) this block belongs to\n+    const u32 start_sector = static_cast<u32>(offset / VolumeWii::BLOCK_TOTAL_SIZE);\n+    const u32 end_sector = static_cast<u32>((offset + sz) / VolumeWii::BLOCK_TOTAL_SIZE);\n+    const auto it = std::ranges::find_if(partitions, [&](const PartitionInfo& p) {\n+      const u32 p_start = static_cast<u32>(p.data_offset / VolumeWii::BLOCK_TOTAL_SIZE);\n+      const u32 p_end =\n+          static_cast<u32>((p.data_offset + p.data_size) / VolumeWii::BLOCK_TOTAL_SIZE);\n+      return start_sector >= p_start && end_sector <= p_end;\n+    });\n+    const PartitionInfo* pi = (it != partitions.end()) ? &*it : nullptr;\n+\n+    bool is_used = true;\n+\n+    if (pi)', 'path': 'Source/Core/DiscIO/WbfsBlob.cpp', 'commit_id': '24b41d58df2315831b74f76b95417f2739d02f9d', 'original_commit_id': '24b41d58df2315831b74f76b95417f2739d02f9d', 'user': {'login': 'phire', 'id': 138484, 'node_id': 'MDQ6VXNlcjEzODQ4NA==', 'avatar_url': 'https://avatars.githubusercontent.com/u/138484?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/phire', 'html_url': 'https://github.com/phire', 'followers_url': 'https://api.github.com/users/phire/followers', 'following_url': 'https://api.github.com/users/phire/following{/other_user}', 'gists_url': 'https://api.github.com/users/phire/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/phire/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/phire/subscriptions', 'organizations_url': 'https://api.github.com/users/phire/orgs', 'repos_url': 'https://api.github.com/users/phire/repos', 'events_url': 'https://api.github.com/users/phire/events{/privacy}', 'received_events_url': 'https://api.github.com/users/phire/received_events', 'type': 'User', 'user_view_type': 'public', 'site_admin': False}, 'body': 'Put the result of `find_if` directly into pi\n\nThen you can skip the weird conversion to nullptr and do the check here\n\n```suggestion\n    if (pi != partitions.end())\n```', 'created_at': '2026-07-18T21:51:02Z', 'updated_at': '2026-07-18T22:26:23Z', 'html_url': 'https://github.com/dolphin-emu/dolphin/pull/14731#discussion_r3609258421', 'pull_request_url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/14731', '_links': {'self': {'href': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/comments/3609258421'}, 'html': {'href': 'https://github.com/dolphin-emu/dolphin/pull/14731#discussion_r3609258421'}, 'pull_request': {'href': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/14731'}}, 'reactions': {'url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/comments/3609258421/reactions', 'total_count': 0, '+1': 0, '-1': 0, 'laugh': 0, 'hooray': 0, 'confused': 0, 'heart': 0, 'rocket': 0, 'eyes': 0}, 'start_line': None, 'original_start_line': None, 'start_side': None, 'line': 531, 'original_line': 531, 'side': 'RIGHT', 'author_association': 'MEMBER', 'original_position': 438, 'position': 438, 'subject_type': 'line'}, 'pull_request': {'url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/14731', 'id': 4056977334, 'node_id': 'PR_kwDOALCn2M7x0I-2', 'html_url': 'https://github.com/dolphin-emu/dolphin/pull/14731', 'diff_url': 'https://github.com/dolphin-emu/dolphin/pull/14731.diff', 'patch_url': 'https://github.com/dolphin-emu/dolphin/pull/14731.patch', 'issue_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/14731', 'number': 14731, 'state': 'open', 'locked': False, 'title': 'Convert To WBFS Support', 'user': {'login': 'thethiny', 'id': 6018214, 'node_id': 'MDQ6VXNlcjYwMTgyMTQ=', 'avatar_url': 'https://avatars.githubusercontent.com/u/6018214?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/thethiny', 'html_url': 'https://github.com/thethiny', 'followers_url': 'https://api.github.com/users/thethiny/followers', 'following_url': 'https://api.github.com/users/thethiny/following{/other_user}', 'gists_url': 'https://api.github.com/users/thethiny/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/thethiny/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/thethiny/subscriptions', 'organizations_url': 'https://api.github.com/users/thethiny/orgs', 'repos_url': 'https://api.github.com/users/thethiny/repos', 'events_url': 'https://api.github.com/users/thethiny/events{/privacy}', 'received_events_url': 'https://api.github.com/users/thethiny/received_events', 'type': 'User', 'user_view_type': 'public', 'site_admin': False}, 'body': "This PR introduces Conversion **to** WBFS support. WBFS is the format that is used by USB Loaders on a real Wii device.\r\n\r\n## Design decisions & hardcoded values\r\nThe writer uses fixed sector sizes that match what [libwbfs (the reference implementation by kwiirk)](https://github.com/kwiirk/wbfs/blob/master/libwbfs/libwbfs.c#L128-L134) computes for a standard single-layer Wii disc. These 2 hardcodes are stable and work correctly across all my testings.\r\n- HD sector shift: 9 (512 bytes)\r\n- WBFS sector shift: 21 (2 MiB)\r\nThese are not configurable via the UI. All existing WBFS tools use these values, and since the aim is to support USB Loaders then this has been tested and it is working on a real Wii.\r\n\r\nConverting from WBFS is not enabled. The existing `WbfsFileReader` reports `DataSizeType::UpperBound`, and `ShouldAllowConversion()` requires `Accurate`. I am able to support this but since it was hardcoded by the Dolphin team I thought a discussion is warranted.\r\n\r\n## Testing\r\n- Verified with DolphinTool header and DolphinTool verify\r\n- Verified with wit FILETYPE and wit DUMP (Wiimm's ISO Tools recognizes valid WBFS structure, partitions, encryption)\r\n- Tested ISO to WBFS and RVZ to WBFS conversions\r\n- Output file sizes match Wii Backup Manager when scrubbing is enabled (~0.1% difference), works when scrubbing is disabled.\r\n- Output WBFS files play correctly in Dolphin\r\n- Output WBFS files play correctly on a real Wii using USB Loader GX e25c4f3\r\n", 'created_at': '2026-07-15T01:16:25Z', 'updated_at': '2026-07-18T22:16:59Z', 'closed_at': None, 'merged_at': None, 'merge_commit_sha': '228f93416dd80eb09da834ad7852c8eaa4d9212b', 'assignees': [], 'requested_reviewers': [], 'requested_teams': [], 'labels': [], 'milestone': None, 'draft': False, 'commits_url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/14731/commits', 'review_comments_url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/14731/comments', 'review_comment_url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/comments{/number}', 'comments_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/14731/comments', 'statuses_url': 'https://api.github.com/repos/dolphin-emu/dolphin/statuses/24b41d58df2315831b74f76b95417f2739d02f9d', 'head': {'label': 'thethiny:wbfs-conversion', 'ref': 'wbfs-conversion', 'sha': '24b41d58df2315831b74f76b95417f2739d02f9d', 'user': {'login': 'thethiny', 'id': 6018214, 'node_id': 'MDQ6VXNlcjYwMTgyMTQ=', 'avatar_url': 'https://avatars.githubusercontent.com/u/6018214?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/thethiny', 'html_url': 'https://github.com/thethiny', 'followers_url': 'https://api.github.com/users/thethiny/followers', 'following_url': 'https://api.github.com/users/thethiny/following{/other_user}', 'gists_url': 'https://api.github.com/users/thethiny/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/thethiny/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/thethiny/subscriptions', 'organizations_url': 'https://api.github.com/users/thethiny/orgs', 'repos_url': 'https://api.github.com/users/thethiny/repos', 'events_url': 'https://api.github.com/users/thethiny/events{/privacy}', 'received_events_url': 'https://api.github.com/users/thethiny/received_events', 'type': 'User', 'user_view_type': 'public', 'site_admin': False}, 'repo': {'id': 1298654395, 'node_id': 'R_kgDOTWfkuw', 'name': 'dolphin', 'full_name': 'thethiny/dolphin', 'private': False, 'owner': {'login': 'thethiny', 'id': 6018214, 'node_id': 'MDQ6VXNlcjYwMTgyMTQ=', 'avatar_url': 'https://avatars.githubusercontent.com/u/6018214?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/thethiny', 'html_url': 'https://github.com/thethiny', 'followers_url': 'https://api.github.com/users/thethiny/followers', 'following_url': 'https://api.github.com/users/thethiny/following{/other_user}', 'gists_url': 'https://api.github.com/users/thethiny/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/thethiny/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/thethiny/subscriptions', 'organizations_url': 'https://api.github.com/users/thethiny/orgs', 'repos_url': 'https://api.github.com/users/thethiny/repos', 'events_url': 'https://api.github.com/users/thethiny/events{/privacy}', 'received_events_url': 'https://api.github.com/users/thethiny/received_events', 'type': 'User', 'user_view_type': 'public', 'site_admin': False}, 'html_url': 'https://github.com/thethiny/dolphin', 'description': 'Dolphin is a GameCube / Wii emulator, allowing you to play games for these two platforms on PC with improvements.', 'fork': True, 'url': 'https://api.github.com/repos/thethiny/dolphin', 'forks_url': 'https://api.github.com/repos/thethiny/dolphin/forks', 'keys_url': 'https://api.github.com/repos/thethiny/dolphin/keys{/key_id}', 'collaborators_url': 'https://api.github.com/repos/thethiny/dolphin/collaborators{/collaborator}', 'teams_url': 'https://api.github.com/repos/thethiny/dolphin/teams', 'hooks_url': 'https://api.github.com/repos/thethiny/dolphin/hooks', 'issue_events_url': 'https://api.github.com/repos/thethiny/dolphin/issues/events{/number}', 'events_url': 'https://api.github.com/repos/thethiny/dolphin/events', 'assignees_url': 'https://api.github.com/repos/thethiny/dolphin/assignees{/user}', 'branches_url': 'https://api.github.com/repos/thethiny/dolphin/branches{/branch}', 'tags_url': 'https://api.github.com/repos/thethiny/dolphin/tags', 'blobs_url': 'https://api.github.com/repos/thethiny/dolphin/git/blobs{/sha}', 'git_tags_url': 'https://api.github.com/repos/thethiny/dolphin/git/tags{/sha}', 'git_refs_url': 'https://api.github.com/repos/thethiny/dolphin/git/refs{/sha}', 'trees_url': 'https://api.github.com/repos/thethiny/dolphin/git/trees{/sha}', 'statuses_url': 'https://api.github.com/repos/thethiny/dolphin/statuses/{sha}', 'languages_url': 'https://api.github.com/repos/thethiny/dolphin/languages', 'stargazers_url': 'https://api.github.com/repos/thethiny/dolphin/stargazers', 'contributors_url': 'https://api.github.com/repos/thethiny/dolphin/contributors', 'subscribers_url': 'https://api.github.com/repos/thethiny/dolphin/subscribers', 'subscription_url': 'https://api.github.com/repos/thethiny/dolphin/subscription', 'commits_url': 'https://api.github.com/repos/thethiny/dolphin/commits{/sha}', 'git_commits_url': 'https://api.github.com/repos/thethiny/dolphin/git/commits{/sha}', 'comments_url': 'https://api.github.com/repos/thethiny/dolphin/comments{/number}', 'issue_comment_url': 'https://api.github.com/repos/thethiny/dolphin/issues/comments{/number}', 'contents_url': 'https://api.github.com/repos/thethiny/dolphin/contents/{+path}', 'compare_url': 'https://api.github.com/repos/thethiny/dolphin/compare/{base}...{head}', 'merges_url': 'https://api.github.com/repos/thethiny/dolphin/merges', 'archive_url': 'https://api.github.com/repos/thethiny/dolphin/{archive_format}{/ref}', 'downloads_url': 'https://api.github.com/repos/thethiny/dolphin/downloads', 'issues_url': 'https://api.github.com/repos/thethiny/dolphin/issues{/number}', 'pulls_url': 'https://api.github.com/repos/thethiny/dolphin/pulls{/number}', 'milestones_url': 'https://api.github.com/repos/thethiny/dolphin/milestones{/number}', 'notifications_url': 'https://api.github.com/repos/thethiny/dolphin/notifications{?since,all,participating}', 'labels_url': 'https://api.github.com/repos/thethiny/dolphin/labels{/name}', 'releases_url': 'https://api.github.com/repos/thethiny/dolphin/releases{/id}', 'deployments_url': 'https://api.github.com/repos/thethiny/dolphin/deployments', 'created_at': '2026-07-12T22:09:13Z', 'updated_at': '2026-07-12T22:09:13Z', 'pushed_at': '2026-07-18T20:35:03Z', 'git_url': 'git://github.com/thethiny/dolphin.git', 'ssh_url': 'git@github.com:thethiny/dolphin.git', 'clone_url': 'https://github.com/thethiny/dolphin.git', 'svn_url': 'https://github.com/thethiny/dolphin', 'homepage': 'https://dolphin-emu.org', 'size': 515471, 'stargazers_count': 0, 'watchers_count': 0, 'language': None, 'has_issues': False, 'has_projects': True, 'has_downloads': True, 'has_wiki': True, 'has_pages': False, 'has_discussions': False, 'forks_count': 0, 'mirror_url': None, 'archived': False, 'disabled': False, 'open_issues_count': 0, 'license': {'key': 'other', 'name': 'Other', 'spdx_id': 'NOASSERTION', 'url': None, 'node_id': 'MDc6TGljZW5zZTA='}, 'allow_forking': True, 'is_template': False, 'web_commit_signoff_required': False, 'has_pull_requests': True, 'pull_request_creation_policy': 'all', 'topics': [], 'visibility': 'public', 'forks': 0, 'open_issues': 0, 'watchers': 0, 'default_branch': 'master', 'allow_squash_merge': True, 'allow_merge_commit': True, 'allow_rebase_merge': True, 'allow_auto_merge': False, 'delete_branch_on_merge': False, 'allow_update_branch': False, 'use_squash_pr_title_as_default': False, 'squash_merge_commit_message': 'COMMIT_MESSAGES', 'squash_merge_commit_title': 'COMMIT_OR_PR_TITLE', 'merge_commit_message': 'PR_TITLE', 'merge_commit_title': 'MERGE_MESSAGE'}}, 'base': {'label': 'dolphin-emu:master', 'ref': 'master', 'sha': 'd3b2943807dd0073f7767947466dd73cccfef319', 'user': {'login': 'dolphin-emu', 'id': 5050316, 'node_id': 'MDEyOk9yZ2FuaXphdGlvbjUwNTAzMTY=', 'avatar_url': 'https://avatars.githubusercontent.com/u/5050316?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/dolphin-emu', 'html_url': 'https://github.com/dolphin-emu', 'followers_url': 'https://api.github.com/users/dolphin-emu/followers', 'following_url': 'https://api.github.com/users/dolphin-emu/following{/other_user}', 'gists_url': 'https://api.github.com/users/dolphin-emu/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/dolphin-emu/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/dolphin-emu/subscriptions', 'organizations_url': 'https://api.github.com/users/dolphin-emu/orgs', 'repos_url': 'https://api.github.com/users/dolphin-emu/repos', 'events_url': 'https://api.github.com/users/dolphin-emu/events{/privacy}', 'received_events_url': 'https://api.github.com/users/dolphin-emu/received_events', 'type': 'Organization', 'user_view_type': 'public', 'site_admin': False}, 'repo': {'id': 11577304, 'node_id': 'MDEwOlJlcG9zaXRvcnkxMTU3NzMwNA==', 'name': 'dolphin', 'full_name': 'dolphin-emu/dolphin', 'private': False, 'owner': {'login': 'dolphin-emu', 'id': 5050316, 'node_id': 'MDEyOk9yZ2FuaXphdGlvbjUwNTAzMTY=', 'avatar_url': 'https://avatars.githubusercontent.com/u/5050316?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/dolphin-emu', 'html_url': 'https://github.com/dolphin-emu', 'followers_url': 'https://api.github.com/users/dolphin-emu/followers', 'following_url': 'https://api.github.com/users/dolphin-emu/following{/other_user}', 'gists_url': 'https://api.github.com/users/dolphin-emu/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/dolphin-emu/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/dolphin-emu/subscriptions', 'organizations_url': 'https://api.github.com/users/dolphin-emu/orgs', 'repos_url': 'https://api.github.com/users/dolphin-emu/repos', 'events_url': 'https://api.github.com/users/dolphin-emu/events{/privacy}', 'received_events_url': 'https://api.github.com/users/dolphin-emu/received_events', 'type': 'Organization', 'user_view_type': 'public', 'site_admin': False}, 'html_url': 'https://github.com/dolphin-emu/dolphin', 'description': 'Dolphin is a GameCube / Wii emulator, allowing you to play games for these two platforms on PC with improvements.', 'fork': False, 'url': 'https://api.github.com/repos/dolphin-emu/dolphin', 'forks_url': 'https://api.github.com/repos/dolphin-emu/dolphin/forks', 'keys_url': 'https://api.github.com/repos/dolphin-emu/dolphin/keys{/key_id}', 'collaborators_url': 'https://api.github.com/repos/dolphin-emu/dolphin/collaborators{/collaborator}', 'teams_url': 'https://api.github.com/repos/dolphin-emu/dolphin/teams', 'hooks_url': 'https://api.github.com/repos/dolphin-emu/dolphin/hooks', 'issue_events_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/events{/number}', 'events_url': 'https://api.github.com/repos/dolphin-emu/dolphin/events', 'assignees_url': 'https://api.github.com/repos/dolphin-emu/dolphin/assignees{/user}', 'branches_url': 'https://api.github.com/repos/dolphin-emu/dolphin/branches{/branch}', 'tags_url': 'https://api.github.com/repos/dolphin-emu/dolphin/tags', 'blobs_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/blobs{/sha}', 'git_tags_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/tags{/sha}', 'git_refs_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/refs{/sha}', 'trees_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/trees{/sha}', 'statuses_url': 'https://api.github.com/repos/dolphin-emu/dolphin/statuses/{sha}', 'languages_url': 'https://api.github.com/repos/dolphin-emu/dolphin/languages', 'stargazers_url': 'https://api.github.com/repos/dolphin-emu/dolphin/stargazers', 'contributors_url': 'https://api.github.com/repos/dolphin-emu/dolphin/contributors', 'subscribers_url': 'https://api.github.com/repos/dolphin-emu/dolphin/subscribers', 'subscription_url': 'https://api.github.com/repos/dolphin-emu/dolphin/subscription', 'commits_url': 'https://api.github.com/repos/dolphin-emu/dolphin/commits{/sha}', 'git_commits_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/commits{/sha}', 'comments_url': 'https://api.github.com/repos/dolphin-emu/dolphin/comments{/number}', 'issue_comment_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/comments{/number}', 'contents_url': 'https://api.github.com/repos/dolphin-emu/dolphin/contents/{+path}', 'compare_url': 'https://api.github.com/repos/dolphin-emu/dolphin/compare/{base}...{head}', 'merges_url': 'https://api.github.com/repos/dolphin-emu/dolphin/merges', 'archive_url': 'https://api.github.com/repos/dolphin-emu/dolphin/{archive_format}{/ref}', 'downloads_url': 'https://api.github.com/repos/dolphin-emu/dolphin/downloads', 'issues_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues{/number}', 'pulls_url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls{/number}', 'milestones_url': 'https://api.github.com/repos/dolphin-emu/dolphin/milestones{/number}', 'notifications_url': 'https://api.github.com/repos/dolphin-emu/dolphin/notifications{?since,all,participating}', 'labels_url': 'https://api.github.com/repos/dolphin-emu/dolphin/labels{/name}', 'releases_url': 'https://api.github.com/repos/dolphin-emu/dolphin/releases{/id}', 'deployments_url': 'https://api.github.com/repos/dolphin-emu/dolphin/deployments', 'created_at': '2013-07-22T09:07:57Z', 'updated_at': '2026-07-18T18:44:16Z', 'pushed_at': '2026-07-18T10:34:54Z', 'git_url': 'git://github.com/dolphin-emu/dolphin.git', 'ssh_url': 'git@github.com:dolphin-emu/dolphin.git', 'clone_url': 'https://github.com/dolphin-emu/dolphin.git', 'svn_url': 'https://github.com/dolphin-emu/dolphin', 'homepage': 'https://dolphin-emu.org', 'size': 558448, 'stargazers_count': 15272, 'watchers_count': 15272, 'language': 'C++', 'has_issues': False, 'has_projects': False, 'has_downloads': True, 'has_wiki': True, 'has_pages': False, 'has_discussions': False, 'forks_count': 3162, 'mirror_url': None, 'archived': False, 'disabled': False, 'open_issues_count': 446, 'license': {'key': 'other', 'name': 'Other', 'spdx_id': 'NOASSERTION', 'url': None, 'node_id': 'MDc6TGljZW5zZTA='}, 'allow_forking': True, 'is_template': False, 'web_commit_signoff_required': False, 'has_pull_requests': True, 'pull_request_creation_policy': 'all', 'topics': ['cpp', 'emulation', 'emulator', 'gamecube', 'wii'], 'visibility': 'public', 'forks': 3162, 'open_issues': 446, 'watchers': 15272, 'default_branch': 'master', 'allow_squash_merge': False, 'allow_merge_commit': True, 'allow_rebase_merge': False, 'allow_auto_merge': False, 'delete_branch_on_merge': False, 'allow_update_branch': False, 'use_squash_pr_title_as_default': False, 'squash_merge_commit_message': 'COMMIT_MESSAGES', 'squash_merge_commit_title': 'COMMIT_OR_PR_TITLE', 'merge_commit_message': 'PR_TITLE', 'merge_commit_title': 'MERGE_MESSAGE'}}, '_links': {'self': {'href': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/14731'}, 'html': {'href': 'https://github.com/dolphin-emu/dolphin/pull/14731'}, 'issue': {'href': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/14731'}, 'comments': {'href': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/14731/comments'}, 'review_comments': {'href': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/14731/comments'}, 'review_comment': {'href': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/comments{/number}'}, 'commits': {'href': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls/14731/commits'}, 'statuses': {'href': 'https://api.github.com/repos/dolphin-emu/dolphin/statuses/24b41d58df2315831b74f76b95417f2739d02f9d'}}, 'author_association': 'NONE', 'auto_merge': None, 'assignee': None, 'active_lock_reason': None}, 'repository': {'id': 11577304, 'node_id': 'MDEwOlJlcG9zaXRvcnkxMTU3NzMwNA==', 'name': 'dolphin', 'full_name': 'dolphin-emu/dolphin', 'private': False, 'owner': {'login': 'dolphin-emu', 'id': 5050316, 'node_id': 'MDEyOk9yZ2FuaXphdGlvbjUwNTAzMTY=', 'avatar_url': 'https://avatars.githubusercontent.com/u/5050316?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/dolphin-emu', 'html_url': 'https://github.com/dolphin-emu', 'followers_url': 'https://api.github.com/users/dolphin-emu/followers', 'following_url': 'https://api.github.com/users/dolphin-emu/following{/other_user}', 'gists_url': 'https://api.github.com/users/dolphin-emu/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/dolphin-emu/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/dolphin-emu/subscriptions', 'organizations_url': 'https://api.github.com/users/dolphin-emu/orgs', 'repos_url': 'https://api.github.com/users/dolphin-emu/repos', 'events_url': 'https://api.github.com/users/dolphin-emu/events{/privacy}', 'received_events_url': 'https://api.github.com/users/dolphin-emu/received_events', 'type': 'Organization', 'user_view_type': 'public', 'site_admin': False}, 'html_url': 'https://github.com/dolphin-emu/dolphin', 'description': 'Dolphin is a GameCube / Wii emulator, allowing you to play games for these two platforms on PC with improvements.', 'fork': False, 'url': 'https://api.github.com/repos/dolphin-emu/dolphin', 'forks_url': 'https://api.github.com/repos/dolphin-emu/dolphin/forks', 'keys_url': 'https://api.github.com/repos/dolphin-emu/dolphin/keys{/key_id}', 'collaborators_url': 'https://api.github.com/repos/dolphin-emu/dolphin/collaborators{/collaborator}', 'teams_url': 'https://api.github.com/repos/dolphin-emu/dolphin/teams', 'hooks_url': 'https://api.github.com/repos/dolphin-emu/dolphin/hooks', 'issue_events_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/events{/number}', 'events_url': 'https://api.github.com/repos/dolphin-emu/dolphin/events', 'assignees_url': 'https://api.github.com/repos/dolphin-emu/dolphin/assignees{/user}', 'branches_url': 'https://api.github.com/repos/dolphin-emu/dolphin/branches{/branch}', 'tags_url': 'https://api.github.com/repos/dolphin-emu/dolphin/tags', 'blobs_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/blobs{/sha}', 'git_tags_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/tags{/sha}', 'git_refs_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/refs{/sha}', 'trees_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/trees{/sha}', 'statuses_url': 'https://api.github.com/repos/dolphin-emu/dolphin/statuses/{sha}', 'languages_url': 'https://api.github.com/repos/dolphin-emu/dolphin/languages', 'stargazers_url': 'https://api.github.com/repos/dolphin-emu/dolphin/stargazers', 'contributors_url': 'https://api.github.com/repos/dolphin-emu/dolphin/contributors', 'subscribers_url': 'https://api.github.com/repos/dolphin-emu/dolphin/subscribers', 'subscription_url': 'https://api.github.com/repos/dolphin-emu/dolphin/subscription', 'commits_url': 'https://api.github.com/repos/dolphin-emu/dolphin/commits{/sha}', 'git_commits_url': 'https://api.github.com/repos/dolphin-emu/dolphin/git/commits{/sha}', 'comments_url': 'https://api.github.com/repos/dolphin-emu/dolphin/comments{/number}', 'issue_comment_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues/comments{/number}', 'contents_url': 'https://api.github.com/repos/dolphin-emu/dolphin/contents/{+path}', 'compare_url': 'https://api.github.com/repos/dolphin-emu/dolphin/compare/{base}...{head}', 'merges_url': 'https://api.github.com/repos/dolphin-emu/dolphin/merges', 'archive_url': 'https://api.github.com/repos/dolphin-emu/dolphin/{archive_format}{/ref}', 'downloads_url': 'https://api.github.com/repos/dolphin-emu/dolphin/downloads', 'issues_url': 'https://api.github.com/repos/dolphin-emu/dolphin/issues{/number}', 'pulls_url': 'https://api.github.com/repos/dolphin-emu/dolphin/pulls{/number}', 'milestones_url': 'https://api.github.com/repos/dolphin-emu/dolphin/milestones{/number}', 'notifications_url': 'https://api.github.com/repos/dolphin-emu/dolphin/notifications{?since,all,participating}', 'labels_url': 'https://api.github.com/repos/dolphin-emu/dolphin/labels{/name}', 'releases_url': 'https://api.github.com/repos/dolphin-emu/dolphin/releases{/id}', 'deployments_url': 'https://api.github.com/repos/dolphin-emu/dolphin/deployments', 'created_at': '2013-07-22T09:07:57Z', 'updated_at': '2026-07-18T18:44:16Z', 'pushed_at': '2026-07-18T10:34:54Z', 'git_url': 'git://github.com/dolphin-emu/dolphin.git', 'ssh_url': 'git@github.com:dolphin-emu/dolphin.git', 'clone_url': 'https://github.com/dolphin-emu/dolphin.git', 'svn_url': 'https://github.com/dolphin-emu/dolphin', 'homepage': 'https://dolphin-emu.org', 'size': 558448, 'stargazers_count': 15272, 'watchers_count': 15272, 'language': 'C++', 'has_issues': False, 'has_projects': False, 'has_downloads': True, 'has_wiki': True, 'has_pages': False, 'has_discussions': False, 'forks_count': 3162, 'mirror_url': None, 'archived': False, 'disabled': False, 'open_issues_count': 446, 'license': {'key': 'other', 'name': 'Other', 'spdx_id': 'NOASSERTION', 'url': None, 'node_id': 'MDc6TGljZW5zZTA='}, 'allow_forking': True, 'is_template': False, 'web_commit_signoff_required': False, 'has_pull_requests': True, 'pull_request_creation_policy': 'all', 'topics': ['cpp', 'emulation', 'emulator', 'gamecube', 'wii'], 'visibility': 'public', 'forks': 3162, 'open_issues': 446, 'watchers': 15272, 'default_branch': 'master', 'custom_properties': {}}, 'organization': {'login': 'dolphin-emu', 'id': 5050316, 'node_id': 'MDEyOk9yZ2FuaXphdGlvbjUwNTAzMTY=', 'url': 'https://api.github.com/orgs/dolphin-emu', 'repos_url': 'https://api.github.com/orgs/dolphin-emu/repos', 'events_url': 'https://api.github.com/orgs/dolphin-emu/events', 'hooks_url': 'https://api.github.com/orgs/dolphin-emu/hooks', 'issues_url': 'https://api.github.com/orgs/dolphin-emu/issues', 'members_url': 'https://api.github.com/orgs/dolphin-emu/members{/member}', 'public_members_url': 'https://api.github.com/orgs/dolphin-emu/public_members{/member}', 'avatar_url': 'https://avatars.githubusercontent.com/u/5050316?v=4', 'description': ''}, 'sender': {'login': 'phire', 'id': 138484, 'node_id': 'MDQ6VXNlcjEzODQ4NA==', 'avatar_url': 'https://avatars.githubusercontent.com/u/138484?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/phire', 'html_url': 'https://github.com/phire', 'followers_url': 'https://api.github.com/users/phire/followers', 'following_url': 'https://api.github.com/users/phire/following{/other_user}', 'gists_url': 'https://api.github.com/users/phire/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/phire/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/phire/subscriptions', 'organizations_url': 'https://api.github.com/users/phire/orgs', 'repos_url': 'https://api.github.com/users/phire/repos', 'events_url': 'https://api.github.com/users/phire/events{/privacy}', 'received_events_url': 'https://api.github.com/users/phire/received_events', 'type': 'User', 'user_view_type': 'public', 'site_admin': False}, 'installation': {'id': 35437981, 'node_id': 'MDIzOkludGVncmF0aW9uSW5zdGFsbGF0aW9uMzU0Mzc5ODE='}}, 'type': 'raw_gh_hook'}