exporting episodes and movies from emby to csv
This commit is contained in:
parent
23d48f1d52
commit
bac85f6bd1
10
README.md
10
README.md
|
@ -20,6 +20,8 @@ Detect tv show filenames by querying the publicly available [tvmaze.com](https:/
|
|||
Episodes are named in this style, a more flexible solution is in pending:
|
||||
**{show-name}/Season {nr}/show-name - S{nr}E{nr} - {episode-name}.{ext}**
|
||||
|
||||
## db_export
|
||||
Export the library to csv files. Calles the Emby API to get a list of movies and episodes and exports this to a convenient set ov CSV files.
|
||||
|
||||
## setup
|
||||
### install
|
||||
|
@ -39,5 +41,9 @@ Duplicate the config.sample file to a file named *config* and set the following
|
|||
* `moviepath`: Root folder where the organized movie files will go.
|
||||
* `tvpath`: Root folder where the organized tv episodes will go.
|
||||
* `ext`: A space separated list of valid media file extensions to easily filter out none media related files.
|
||||
* `log_file`: Path to a file to output all renaming done to keep track and check for any errors.
|
||||
* `movie_db_api`: Register and get your themoviedb.com **API Key (v3 auth)** acces from [here](https://www.themoviedb.org/settings/api).
|
||||
* `log_path`: Path to a folder to output all renaming done to keep track and check for any errors and safe csv files.
|
||||
* `movie_db_api`: Register and get your themoviedb.com **API Key (v3 auth)** acces from [here](https://www.themoviedb.org/settings/api).
|
||||
Emby integration:
|
||||
* `emby_url`: url where your emby instance is reachable
|
||||
* `emby_user_id`: user id of your emby user
|
||||
* `emby_api_key`: api key for your user on emby
|
||||
|
|
|
@ -97,6 +97,7 @@ def sel_handler(menu_item, config):
|
|||
if menu_item == 'All':
|
||||
moviesort.main(config)
|
||||
tvsort.main(config, tvsort_id)
|
||||
db_export.main(config)
|
||||
elif menu_item == 'Movies':
|
||||
moviesort.main(config)
|
||||
elif menu_item == 'TV shows':
|
||||
|
|
121
src/db_export.py
121
src/db_export.py
|
@ -20,7 +20,7 @@ def get_items(config):
|
|||
# episodes
|
||||
url = (f'{emby_url}/Users/{emby_user_id}/Items?api_key={emby_api_key}' +
|
||||
'&IncludeItemTypes=Episode&Recursive=true&StartIndex=0' +
|
||||
'&Fields=DateCreated,MediaStreams,MediaSources'
|
||||
'&Fields=DateCreated,Genres,MediaStreams,MediaSources,Overview,ProviderIds'
|
||||
'&SortBy=DateCreated&SortOrder=Descending&IsMissing=false')
|
||||
|
||||
r = requests.get(url)
|
||||
|
@ -116,13 +116,128 @@ def write_movie_files(movie_info_csv, movie_tech_csv, movie_seen, config):
|
|||
# movie by new
|
||||
file_path = path.join(log_folder, 'movienew')
|
||||
with open(file_path, 'w') as f:
|
||||
f.writelines(movie_seen)
|
||||
for line in movie_seen:
|
||||
f.write(line + '\n')
|
||||
|
||||
|
||||
def parse_episodes(all_episodes):
|
||||
""" loop through all episodes """
|
||||
episode_info_csv = []
|
||||
episode_tech_csv = []
|
||||
episode_seen = []
|
||||
|
||||
for episode in all_episodes:
|
||||
if episode['ParentIndexNumber'] == 0:
|
||||
# not a real episode
|
||||
continue
|
||||
# general
|
||||
episode_name = episode['Name']
|
||||
episode_id = episode['IndexNumber']
|
||||
try:
|
||||
overview = episode['Overview'].replace('\n\n', ' ').replace('\n', ' ')
|
||||
except KeyError:
|
||||
overview = 'NA'
|
||||
try:
|
||||
imdb = episode['ProviderIds']['Imdb']
|
||||
except KeyError:
|
||||
imdb = 'NA'
|
||||
played = episode['UserData']['Played']
|
||||
genres = ', '.join(episode['Genres'])
|
||||
season_name = episode['SeasonName']
|
||||
series_name = episode['SeriesName']
|
||||
# media
|
||||
for i in episode['MediaSources']:
|
||||
if i['Protocol'] == 'File':
|
||||
file_name = path.basename(i['Path'])
|
||||
file_id = i['Name']
|
||||
duration_min = round(i['RunTimeTicks'] / 600000000)
|
||||
filesize_MB = round(i['Size'] / 1024 / 1024)
|
||||
for j in i['MediaStreams']:
|
||||
if j['Type'] == 'Video':
|
||||
image_width = j['Width']
|
||||
image_height = j['Height']
|
||||
avg_bitrate_MB = round(j['BitRate'] / 1024 / 1024, 2)
|
||||
codec = j['Codec']
|
||||
# found it
|
||||
break
|
||||
# found it
|
||||
break
|
||||
# info csv
|
||||
info_dict = {}
|
||||
info_dict['series_name'] = series_name
|
||||
info_dict['file_id'] = file_id
|
||||
info_dict['season_name'] = season_name
|
||||
info_dict['episode_id'] = episode_id
|
||||
info_dict['episode_name'] = episode_name
|
||||
info_dict['imdb'] = imdb
|
||||
info_dict['genres'] = genres
|
||||
info_dict['overview'] = overview
|
||||
info_dict['duration_min'] = duration_min
|
||||
episode_info_csv.append(info_dict)
|
||||
# technical csv
|
||||
tech_dict = {}
|
||||
tech_dict['file_name'] = file_name
|
||||
tech_dict['duration_min'] = duration_min
|
||||
tech_dict['filesize_MB'] = filesize_MB
|
||||
tech_dict['image_width'] = image_width
|
||||
tech_dict['image_height'] = image_height
|
||||
tech_dict['avg_bitrate_MB'] = avg_bitrate_MB
|
||||
tech_dict['codec'] = codec
|
||||
episode_tech_csv.append(tech_dict)
|
||||
# seen or unseen
|
||||
if played == True:
|
||||
icon = '[X]'
|
||||
elif played == False:
|
||||
icon = '[ ]'
|
||||
seen_line = f'{icon} {file_id}'
|
||||
episode_seen.append(seen_line)
|
||||
return episode_info_csv, episode_tech_csv, episode_seen
|
||||
|
||||
|
||||
def write_episode_files(episode_info_csv, episode_tech_csv, episode_seen, config):
|
||||
""" writes the csv files to disk """
|
||||
# log_folder = config['log_folder']
|
||||
log_folder = '/tmp'
|
||||
|
||||
# episode info
|
||||
episode_info_sorted = sorted(episode_info_csv, key=lambda k: k['file_id'])
|
||||
for i in episode_info_sorted:
|
||||
i.pop('file_id', None)
|
||||
file_path = path.join(log_folder, 'episode-info.csv')
|
||||
# open and write
|
||||
with open(file_path, 'w') as f:
|
||||
# take fieldnames from first line
|
||||
fieldnames = episode_info_sorted[0].keys()
|
||||
csv_writer = csv.DictWriter(f, fieldnames)
|
||||
csv_writer.writeheader()
|
||||
csv_writer.writerows(episode_info_sorted)
|
||||
|
||||
# episode tech
|
||||
episode_tech_csv_sorted = sorted(episode_tech_csv, key=lambda k: k['file_name'])
|
||||
file_path = path.join(log_folder, 'episode-tech.csv')
|
||||
# open and write
|
||||
with open(file_path, 'w') as f:
|
||||
# take fieldnames from first line
|
||||
fieldnames = episode_tech_csv_sorted[0].keys()
|
||||
csv_writer = csv.DictWriter(f, fieldnames)
|
||||
csv_writer.writeheader()
|
||||
csv_writer.writerows(episode_tech_csv_sorted)
|
||||
|
||||
# episode by new
|
||||
file_path = path.join(log_folder, 'episodenew')
|
||||
with open(file_path, 'w') as f:
|
||||
for line in episode_seen:
|
||||
f.write(line + '\n')
|
||||
|
||||
|
||||
def main(config):
|
||||
""" write collection to csv """
|
||||
print('recreating db files')
|
||||
# get data
|
||||
all_movies, _ = get_items(config)
|
||||
all_movies, all_episodes = get_items(config)
|
||||
# write movies
|
||||
movie_info_csv, movie_tech_csv, movie_seen = parse_movies(all_movies)
|
||||
write_movie_files(movie_info_csv, movie_tech_csv, movie_seen, config)
|
||||
# write episodes
|
||||
episode_info_csv, episode_tech_csv, episode_seen = parse_episodes(all_episodes)
|
||||
write_episode_files(episode_info_csv, episode_tech_csv, episode_seen, config)
|
||||
|
|
Loading…
Reference in New Issue