54

I'm using adb to sync music on an android phone. Essentially, I rm the existing music directory and push replacement music files.

I'd like to be able to use adb to force a rescan, so that the google music player (and other apps) works properly with the new songs and playlists.

According to How can I refresh MediaStore on Android? you can force a rescan by broadcasting an appropriate intent.

adb provides 'shell am broadcast', which would seem to allow me to force a rescan from adb.

Alternatively I could run a rescan app or reboot, but I'd like to trigger the rescan from adb

What adb command should I issue? The music files and playlists are all in /sdcard/music.

Community
  • 1
  • 1
foosion
  • 7,619
  • 25
  • 65
  • 102

5 Answers5

58

The rescan apps use a media mount intent to kick off the media scanner. You can use am broadcast to send the same intent.

The command is:

adb shell am broadcast -a android.intent.action.MEDIA_MOUNTED -d file:///sdcard
Simon
  • 10,932
  • 50
  • 49
user2892047
  • 696
  • 5
  • 5
  • 31
    I've been using: `adb shell am broadcast -a android.intent.action.MEDIA_MOUNTED -d file:///mnt/sdcard/Music` – foosion Oct 18 '13 at 21:34
  • 1
    I noticed that on Kitkat the rescan doesn't happen right away, only eventually. I don't remember if that was the case on older APIs. Is there a way to force the rescan to happen immediately? – futtetennista Sep 13 '14 at 10:32
  • 2
    @foosion That works on my Nexus 6 running Android 5.1.1, 6.0, and 6.0.1. – Jared Burrows Aug 04 '15 at 03:10
  • 3
    @foosion That **does not work** on my Nexus 6 running Android N preview. I get a security exception. – Jared Burrows Apr 09 '16 at 21:16
  • 3
    @JaredBurrows it requires root on Nougat: adb shell su -c 'am broadcast -a android.intent.action.MEDIA_MOUNTED -d file:///sdcard' – miigotu Sep 09 '16 at 12:27
  • 1
    I got permission denied on android 7 but am rooted and this worked fine for me: `adb shell 'su -c "am broadcast -a android.intent.action.MEDIA_MOUNTED -d file:///mnt/sdcard/Ringtones"'` – mattpr Oct 23 '17 at 09:46
  • `adb shell am broadcast android.intent.action.MEDIA_MOUNTED` seems to work now, without security exception – Ben Winding Sep 14 '21 at 03:17
35

The MEDIA_MOUNTED intent is no longer permitted (post KitKat) for non-system apps; try this instead.

It’s not recursive, though, and has to be run on the exact_file_name, so it’s not a good replacement.

adb shell am broadcast \
    -a android.intent.action.MEDIA_SCANNER_SCAN_FILE \
    -d file:///mnt/sdcard/Music/<exact_file_name>

If you need to rescan recursively, you can use this command (fix paths accordingly):

adb shell "find /mnt/sdcard/Music/ -exec am broadcast \
    -a android.intent.action.MEDIA_SCANNER_SCAN_FILE \
    -d file://{} \\;"

Or like this (if above won't work for you):

adb shell "find /mnt/sdcard/Music/ | while read f; do \
    am broadcast -a android.intent.action.MEDIA_SCANNER_SCAN_FILE \
    -d \"file://${f}\"; done"
doubleDown
  • 8,048
  • 1
  • 32
  • 48
Manas Tungare
  • 607
  • 6
  • 13
  • 1
    It's `android.intent.action.MEDIA_SCANNER_SCAN_FILE`, not `android.intent.action.ACTION_MEDIA_SCANNER_SCAN_FILE`. ACTION_* is the name of the Android variable: https://developer.android.com/reference/android/content/Intent.html#ACTION_MEDIA_SCANNER_SCAN_FILE – rom1v Aug 28 '17 at 10:04
  • 1
    None of these worked for me. This hack did, however: `adb shell ' for ANDROID_MEDIA in $(find /mnt/sdcard/Music/ -type f | sed '\''s/ /\*/g'\''); do am broadcast -a android.intent.action.MEDIA_SCANNER_SCAN_FILE -d "${ANDROID_MEDIA}" done '` – gnucchi Aug 13 '19 at 23:59
  • I get broadcast completed result 0. And stock Moto gallery (Android 5.0) won’t find the picture I just moved from emulated/0 to /storage/sdcard1/Pictures. Why is that ? If I go to storage settings and choose move media to sdcard, then it works. It also works with auto-move-to sdcard app. – Khurshid Alam Aug 13 '23 at 12:40
2

On some Samsung mobiles, you can get a full rescan like this:

am broadcast -a com.samsung.intent.action.MTP_FILE_SCAN -n com.android.providers.media/.MediaScannerReceiver
letsintegreat
  • 3,328
  • 4
  • 18
  • 39
Sander
  • 21
  • 1
1

If you have rooted your phone, you can use this script I’ve written, which has the advantage of keeping track of which files have already been updated:

#!/system/bin/env busybox ash

MUSIC_LIBRARY=/sdcard/MusicLibrary

LAST_UPDATE="$(stat -c %Y "$MUSIC_LIBRARY/.last-update")"

find "$MUSIC_LIBRARY" -type f ! -iname ".last-update" | (
  while read f; do
    if ! test "$LAST_UPDATE" -ge "$(stat -c %Y "$f")"; then
      am broadcast -a android.intent.action.MEDIA_SCANNER_SCAN_FILE -d "file://$f"
      touch "$f"
    else
      echo "Not updated: \`$f'"
    fi
  done
)

touch "$MUSIC_LIBRARY/.last-update"
André Kugland
  • 855
  • 8
  • 20
  • What is the purpose of the "touch" command *after* sending the broadcast? – Michael Feb 04 '22 at 23:14
  • Also, this doesn't seem to work for poking Google Photos to find new pictures that have been rsynced to the device... – Michael Feb 04 '22 at 23:28
  • @Michael, the `touch` is there so that, on the next execution of the script, `! test ...` will return non-zero (*i.e.* "false", in the twisted world of shell scripts). – André Kugland Mar 15 '22 at 21:52
1

Here's a Python script called adb-scan. It uses adb to ask the Android device to rescan the given files.

Example usage:

$ adb-scan Notifications/\*.mp3
Broadcasting: Intent { act=android.intent.action.MEDIA_SCANNER_SCAN_FILE dat=file:///sdcard/Notifications/cough.mp3 flg=0x400000 }
Broadcast completed: result=0
Broadcasting: Intent { act=android.intent.action.MEDIA_SCANNER_SCAN_FILE dat=file:///sdcard/Notifications/harmonica3.mp3 flg=0x400000 }
Broadcast completed: result=0
Broadcasting: Intent { act=android.intent.action.MEDIA_SCANNER_SCAN_FILE dat=file:///sdcard/Notifications/shhh.mp3 flg=0x400000 }
Broadcast completed: result=0
$

Here's the script:

#!/usr/bin/python3
#
# Ask the Android media scanner to check the given files.
#
import sys
import os
import re

sys.argv.pop(0)

if not sys.argv:
   sys.exit('usage: adb-scan files...')

intent = 'android.intent.action.MEDIA_SCANNER_SCAN_FILE'

# Quote certain special characters such as spaces, backslashes and quotes.  In
# particular, don't quote '*' because we want that to be expanded on the
# Android device.
def cleanup(arg):
   if not arg.startswith('/'):
      arg = '/sdcard/' + arg
   arg = re.sub("[ \\'\"]", lambda x: '\\' + x.group(0), arg)
   return arg

script = '''
for i in {args}; do
    [ -e "$i" ] || echo "warning: no such file: $i"
    am broadcast -a "{intent}" -d "file://$i"
done
'''.format(args=' '.join(map(cleanup, sys.argv)),
           intent=intent)

cmd = ['adb', 'shell', script]
os.execvp(cmd[0], cmd)
Waxrat
  • 510
  • 2
  • 11