Movatterモバイル変換


[0]ホーム

URL:


Skip to content
Search Gists
Sign in Sign up

Instantly share code, notes, and snippets.

@upsuper
CreatedFebruary 12, 2023 11:01
    • Star(0)You must be signed in to star a gist
    • Fork(0)You must be signed in to fork a gist
    Save upsuper/31161a78a8c4a7ec3b3b2fa5aee9b02b to your computer and use it in GitHub Desktop.
    Scripts to import from iTunes
    #!/usr/bin/env python3
    importplistlib
    importsqlite3
    importuuid
    fromcollectionsimportdefaultdict
    fromdatetimeimportdatetime
    fromtypingimportNamedTuple
    fromurllib.parseimportunquote
    NAVIDROME_DB="<path>/navidrome.db"
    NAVIDROME_MUSIC_PATH="/home/<user>/Music/"
    NAVIDROME_USER_ID="<user-id>"
    ITUNES_LIBRARY="<path>/iTunes Library.xml"
    classItunesTrack(NamedTuple):
    location:str
    play_count:int
    play_date:datetime|None
    defread_itunes_tracks()->list[ItunesTrack]:
    withopen(ITUNES_LIBRARY,'rb')asf:
    itunes_library=plistlib.load(f)
    base_path=itunes_library['Music Folder']+'Music/'
    result:list[ItunesTrack]= []
    fortrackinitunes_library['Tracks'].values():
    location:str=track['Location']
    assertlocation.startswith(base_path)
    location=unquote(location[len(base_path):])
    if'Play Count'intrack:
    play_count:int=track['Play Count']
    play_date=track['Play Date UTC']
    else:
    play_count=0
    play_date=None
    result.append(ItunesTrack(location,play_count,play_date))
    returnresult
    classNavidromMediaFile(NamedTuple):
    id:str
    path:str
    artist_id:str
    album_id:str
    defread_navidrom_files(db:sqlite3.Connection)->list[NavidromMediaFile]:
    cur=db.cursor()
    result:list[NavidromMediaFile]= []
    for (id,path,artist_id,album_id)incur.execute('\
    SELECT id, path, artist_id, album_id\
    FROM media_file'):
    assertpath.startswith(NAVIDROME_MUSIC_PATH)
    path=path[len(NAVIDROME_MUSIC_PATH):]
    result.append(NavidromMediaFile(id,path,artist_id,album_id))
    returnresult
    classNavidromAnnotation(NamedTuple):
    id:str
    item_id:str
    item_type:str
    play_count:int
    play_date:datetime
    defread_navidrom_annotations(db:sqlite3.Connection)->list[NavidromAnnotation]:
    cur=db.cursor()
    result:list[NavidromAnnotation]= []
    for (id,item_id,item_type,play_count,play_date)incur.execute('\
    SELECT\
    ann_id, item_id, item_type, play_count,\
    play_date as "play_date [timestamp]"\
    FROM annotation\
    WHERE user_id=?', (NAVIDROME_USER_ID,)):
    result.append(NavidromAnnotation(id,item_id,item_type,play_count,play_date))
    returnresult
    defupdate_navidrom_annotations(
    db:sqlite3.Connection,
    itunes_tracks:list[ItunesTrack],
    media_files:list[NavidromMediaFile],
    annotations:list[NavidromAnnotation]):
    insert_table:list[tuple[str,str,str,str,int,datetime]]= []
    update_table:list[tuple[int,str]]= []
    media_file_table= {file.path:fileforfileinmedia_files}
    annotation_table= {
    f'{ann.item_type}:{ann.item_id}': (ann.id,ann.play_count)
    foranninannotations
    }
    albums:dict[str,tuple[int,datetime|None]]=defaultdict(lambda: (0,None))
    artists:dict[str,tuple[int,datetime|None]]=defaultdict(lambda: (0,None))
    defupdate_collection_with(
    collection:dict[str,tuple[int,datetime|None]],
    id:str,
    track:ItunesTrack,
    ):
    (play_count,play_date)=collection[id]
    play_count+=track.play_count
    iftrack.play_dateisnotNoneand \
    (play_dateisNoneorplay_date<track.play_date):
    play_date=track.play_date
    collection[id]= (play_count,play_date)
    deffill_lists(
    item_type:str,
    item_id:str,
    play_count:int,
    play_date:datetime|None):
    ifplay_dateisNone:
    assertplay_count==0
    return
    key=f'{item_type}:{item_id}'
    ifkeyinannotation_table:
    (id,play_count)=annotation_table[key]
    play_count+=track.play_count
    update_table.append((play_count,id))
    else:
    insert_table.append((
    str(uuid.uuid4()),
    NAVIDROME_USER_ID,
    item_id,
    item_type,
    play_count,
    play_date))
    # Fill the command lists for tracks
    fortrackinitunes_tracks:
    file=media_file_table[track.location]
    fill_lists('media_file',file.id,track.play_count,track.play_date)
    update_collection_with(albums,file.album_id,track)
    update_collection_with(artists,file.artist_id,track)
    # Fill the command lists for albums and artists
    for (album_id, (play_count,play_date))inalbums.items():
    fill_lists('album',album_id,play_count,play_date)
    for (artist_id, (play_count,play_date))inartists.items():
    fill_lists('artist',artist_id,play_count,play_date)
    cur=db.cursor()
    cur.executemany('\
    INSERT INTO annotation\
    (ann_id, user_id, item_id, item_type, play_count, play_date)\
    VALUES (?, ?, ?, ?, ?, ?)',insert_table)
    cur.executemany('\
    UPDATE annotation\
    SET play_count=?\
    WHERE ann_id=?',update_table)
    db.commit()
    defmain():
    itunes_tracks=read_itunes_tracks()
    navidrome_db=sqlite3.connect(
    NAVIDROME_DB,
    detect_types=sqlite3.PARSE_DECLTYPES|sqlite3.PARSE_COLNAMES)
    navidrome_files=read_navidrom_files(navidrome_db)
    navidrome_anns=read_navidrom_annotations(navidrome_db)
    update_navidrom_annotations(
    navidrome_db,
    itunes_tracks,
    navidrome_files,
    navidrome_anns)
    if__name__=='__main__':
    main()
    #!/usr/bin/env python3
    importplistlib
    frompathlibimportPath
    fromtypingimportNamedTuple
    fromurllib.parseimportunquote
    ITUNES_LIBRARY="<path>/iTunes Library.xml"
    PLAYLIST_OUTPUT="playlists"
    classItunesTrack(NamedTuple):
    id:int
    location:str
    defmain():
    withopen(ITUNES_LIBRARY,'rb')asf:
    itunes_library=plistlib.load(f)
    base_path=itunes_library['Music Folder']+'Music/'
    track_map:dict[int,str]= {}
    fortrackinitunes_library['Tracks'].values():
    id:int=track['Track ID']
    location:str=track['Location']
    assertlocation.startswith(base_path)
    location=unquote(location[len(base_path):])
    track_map[id]=location
    forplaylistinitunes_library['Playlists']:
    if'Playlist Items'notinplaylist:
    continue
    name=playlist['Name']
    withPath(PLAYLIST_OUTPUT,f'{name}.m3u').open('w')asf:
    f.write('#EXTM3U\n')
    foriteminplaylist['Playlist Items']:
    id=item['Track ID']
    f.write(f'{track_map[id]}\n')
    if__name__=='__main__':
    main()
    Sign up for freeto join this conversation on GitHub. Already have an account?Sign in to comment

    [8]ページ先頭

    ©2009-2025 Movatter.jp