'urllink' is a ComputedIndexField in Sitecore indexs.
For media items, if I rebuild the indexs, the urls that gets stored into index start with '/~/media/...', which is correct.
But if the index strategy is onPublishEndSync, and I do republish on my media items, the urls start with '/sitecore/shell/~/media/...'.
I've checked Sitecore source code, the difference is Context.Site. it's null when rebuilding the index, so it uses '/' as prefix. but it's 'Sitecore shell' when doing publishing. Therefore it's using Context.Site.VirtualFolder of Sitecore Shell, which is '/sitecore/shell'.
I think this is a Sitecore bug. ATM I'm thinking to create my own urlLink ComputedIndexField class and use MediaUrlOptions with AbsolutePath=false as a fix.
Requested Sitecore Support for help. Tested the fix for now, works fine.
Update 1 - 08/12/2014
Sitecore confirmed it's a bug, however second response came back changed to saying this is expected behavior, I'm not happy with the response yet, stilling discussing.
Update 2 - 15/12/2014
Ticket's closed now. Sitecore's solution is to remove this 'urlLink' field from the index in the future(They said they will request this).
Reason being that url should be generated by LinkManager based on current site context. However site context doesn't exist while indexing(For content item you can check the path, but for media item you cannot).
Of course there's another solution is to create your own computeredField to override the logic for media item. However I agree with Sitecore, it feels more right to remove this field from the index.
On top of all that, the initial reason for using the urlLink field was to drop the need for querying Sitecore completely while doing a Search. All the content are coming from Index's stored fields value. But on the other hand, pagination is normally being used for search results, so even there're requests to Sitecore, it shouldn't be a lot.
That'd be all for now, happy to see more opinions and to discuss, thanks!