• Aktuell
    • Tags
    • Beliebt
    • Benutzer
    • Gruppen
    • Suche
    • Registrieren
    • Anmelden

    Prozess und Python Skript für Automatisierung der MP3/Podcast-Veröffentlichung

    Tipps & Tricks
    4
    5
    609
    Lade mehr Beiträge
    • Älteste zuerst
    • Neuste zuerst
    • Meiste Stimmen
    Antworten
    • In einem neuen Thema antworten
    Anmelden zum Antworten
    Dieses Thema wurde gelöscht. Nur Nutzer mit entsprechenden Rechten können es sehen.
    • Andreas BA
      Andreas B
      zuletzt editiert von

      Hallo zusammen

      ich bin ein Neuling in Sachen Skripten mit Python, trotzdem möchte ich hier teilen, wie Predigt-MP3 Veröffentlichung dank ChurchTools REST API bei uns semi-automatisch funktioniert, in der Hoffnung, dass entweder der Prozess oder Code(-Teile) für den einen oder anderen hilfreich sein können.

      Der Prozess sieht grob wie folgt aus:

      • Im Vorfeld wird Serien-Cover im WordPress Modul "Sermon Manager" abgelegt (siehe Spotify Podcast für Beispiele)
      • In ChurchTools werden im Vorfeld am Gottesdienst Event der Prediger sowie im Feld "Weitere Info" in definiertem Format Predigttitel (und falls zutrifft Serie) eingetragen: # Predigttitel, bzw. # Serie | Predigttitel
      • Die Predigt wird während des Gottesdienstes mit einem Audio-Programm aufgenommen und als MP3 mit Namen JJJJ-MM-TT.mp3 in einem Nextcloud-Ordner abgelegt
      • Mithilfe des Skripts wird dann folgendes gemacht:
      1. Die MP3 wird aus definiertem Nextcloud-Ordner abgeholt und auf Bestätigung erfolgter Bearbeitung abgewartet. Hier erfolgt Zuschnitt vom Audio und Anwendung von Makros in Audacity (Mono, Geräuschentfernung, Export einer neuen MP3 in niedrigerem Bitrate, etc.)
      2. Nach Bestätigung läuft das Skript weiter und holt für das Datum des MP3 Files die Prediger- und Titel-Informationen aus dem ChurchTools Event
      3. MP3 Tags werden gesetzt und die Datei entsprechend umbenannt
      4. Es wird geprüft, ob die Predigt bereits im WordPress veröffentlicht ist. Falls nicht wird die MP3 Datei in einen definierten Import Ordner für die Veröffentlichung auf der Webseite hochgeladen (WordPress Modul Sermon Manager + Sermon Manager Importer)
      5. YouTube Link zum Gottesdienst-Video wird ermittelt (anhand einer Playlist, um von Info oder Kinder-Gottesdienst-Videos zu unterscheiden)
      6. Mithilfe von Selenium und chromedriver wird die Predigt importiert (bzw. aktualisiert), indem die URL zum YouTube Video in der Beschreibung hinterlegt wird.
      7. Im Sermon Manager ist ein Podcast RSS Feed eingestellt, welcher bei Apple Podcast, Spotify Podcast und Google Podcast registriert ist
      ### install eyed3 and owncloud python modules beforehand
      # > pip3 install eyed3
      # > pip3 install owncloud
      # > put chromedriver into the directory defined in the cloud_chromedriver_path var below
      # > put cover.jpg to be used as cover image for mp3 tags
      # > for help use: python3 <scriptname>.py -h 
      
      import eyed3
      
      import argparse
      import sys
      import os
      import glob
      import base64
      import json
      
      import datetime
      import time
      from datetime import date, timezone, timedelta
      
      import requests
      import re
      
      import owncloud
      import ftplib
      
      import zipfile
      
      from selenium import webdriver
      from selenium.webdriver.chrome.options import Options
      from selenium.webdriver.common.by import By
      from selenium.webdriver.support.ui import WebDriverWait
      from selenium.webdriver.support import expected_conditions as EC
      
      ################### Variables ######################
      
      ### ChurchTools global vars ###
      
      ct_url = 'https://<MyChurch>.church.tools/api/'  # main ChurchTools API URL
      ct_username = 'churchtools.api@MyChurch.de' # API user name
      ct_password = 'churchtools.api.Password' # API user password
      ct_preacher_serviceid = 19  # serviceId of the preacher service in the CT events response (data > eventServices > serviceId)
      ct_caldomains_bi = [ '2' ] # church branches calender domain ID - (2 = Gottedienste BI)
      ct_caldomains_gt = [ '24' ] # church branches calender domain ID - (24 = Gottedienste GT)
      ct_caldomains = [ '2' ] # 2 = Gottesdienste BI, 24 = Gottedienste GT
      
      
      ### Sermon parcing vars ###
      ct_exclude_titles = [ 'Weitere Infos...', '' ]
      ct_default_lookback_days = 90 # the greater, the longer it takes. Must be set to the most of passed days since the start of the current sermon series, to insure the correct track number in the album
      ct_sermon_tag = '#' # sermon tag indicates the beginning of the sermon description within the even description field. e.g.: "Christmas service #The Star of Bethlehem"
      ct_series_sep = '|' # series separator placed after the series name and before the sermon title. e.g.: "Baptism church service # Following Jesus | The Most Important Decision"
      
      ### Cloud vars
      cloud_url = 'https://cloud.<MyChurch>.de'
      cloud_username = 'Mp3CloudUser'
      cloud_password = 'Mp3CloudUserPassword'
      cloud_download_dirs = [ 'mp3_video_export', 'mp3_audio_mixer' ]
      cloud_upload_dir = 'mp3_web_import'
      cloud_local_dir = '/home/<USER>/nextcloud'
      cloud_chromedriver_path = cloud_local_dir+'/scripts/chromedriver'
      
      ### Selenium chromedriver vars
      driver_url = 'https://chromedriver.storage.googleapis.com/'
      driver_zip = 'chromedriver_mac64.zip'
      driver_version_file = cloud_local_dir+'/scripts/CHROMEDRIVER_VERSION'
      
      ### FTPs vars
      ftp_host = '<MyChurch>.de'
      ftp_username = 'Mp3FtpUser'
      ftp_password = 'Mp3FtpUserPassword'
      
      ### Wordpress vars
      wp_user = 'Mp3WordPressUser'
      wp_password = 'Mp3WordPressUserPassword'
      wp_rest_pass = '1234 abcd 5678 efgh 09jk lmnp'
      wp_url = 'https://<MyChurch.de/wp-admin/'
      wp_rest_url = 'https://<MyChurch>.de/wp-json/wp/v2/'
      wp_sermons = 'edit.php?post_type=wpfc_sermon'
      wp_url_sermons = wp_url+wp_sermons
      wp_url_import = wp_url_sermons+'&page=sermon-manager-import'
      wp_credentials = wp_user+':'+wp_rest_pass
      wp_token = base64.b64encode(wp_credentials.encode())
      wp_header = {'Authorization': 'Basic ' + wp_token.decode('utf-8')}
      
      ### Youtube vars
      yt_url = 'https://www.googleapis.com/youtube/v3/'
      yt_auth_key = 'RegisterAtGoogleAPIstoGetYourAuthKey'
      yt_channel_id = 'YourYouTubeChannelID'
      yt_playlist_id = 'PlaylistIdForChurchServices'
      yt_max_search_results = '4'
      yt_max_playlist_results = '10'
      
      
      ### MP3 tag vars
      mp3_dir = cloud_local_dir+'/put/downloaded/mp3/here'
      mp3_wdir = mp3_dir+'/mp3/from/audacity/are/found/here'
      
      mp3_default_series = 'Einzelne Predigten' # fallback series name
      mp3_default_preacher = 'Max Mustermann' # preacher name to be used if none is provided
      mp3_albumartist = 'My Church'
      mp3_publisher = 'My Church'
      mp3_composer = 'https://<MyChurch>.de/'
      mp3_url_apple = 'https://podcasts.apple.com/de/podcast/id000000000000'
      mp3_genre = 'Podcast'
      mp3_cover = 'cover.jpg'
      
      
      ################# Functions #######################
      
      def get_args():
      
          parser = argparse.ArgumentParser(
              description='Arguments for MP3 publishing')
          parser.add_argument('-f', '--mp3file', type=str, action='store', required=False,
                              help='Use specific local mp3 file instead of making a date guess for the last Sunday and downloading one from the cloud')
          parser.add_argument('-r', '--remotemp3', default=False, required=False,  action='store_true',
                              help='If no owncloud / nextCloud client is installed and the cloud_local_dir is undefined then use this flag to download mp3 from folders defined in cloud_download_dirs')
          parser.add_argument('-d', '--date', type=str, action='store', required=False,
                              help='Use provided date instead of most recent Sunday')
          parser.add_argument('-c', '--church', type=str, required=False, default='BI', action='store',
                              help='BI (for Bielefeld) or GT (for Guetersloh)')
          parser.add_argument('-s', '--single', default=False, required=False,  action='store_true',
                              help='Single sermon (not part of series) - works faster!')
          parser.add_argument('-b', '--lookbackdays', type=int, default=ct_default_lookback_days, required=False, action='store',
                              help='Past days to look back for sermon series. The greater, the longer it takes. Must be set to the most of passed days since the start of the current sermon series, to insure the correct track number in the album. Default: 90')
          parser.add_argument('-p', '--publish', default=False, required=False,  action='store_true',
                              help='Publish the mp3 after tagging')
          parser.add_argument('-n', '--nextcloud', default=False, required=False,  action='store_true',
                              help='Use nextCloud instead of FTP for the MP3 upload. Works only if -p (--publish) is provided')
          parser.add_argument('-q', '--quiet', default=False, required=False,  action='store_true',
                              help='Run the script without user interaction, continue automatically')
          args = parser.parse_args()
          return args
      
      def get_last_sunday_date(usedate):
      	# check if it's Sunday. If not use last Sunday before this date
      	offset = (usedate.weekday() - 6) % 7
      	last_sunday_date = usedate - timedelta(days=offset)
      	return last_sunday_date
      
      def get_lookback_fromdate(todate, lookback_days):
      	fromdate = todate - datetime.timedelta(days=lookback_days)
      	return fromdate
      
      def get_nextday_str(usedate_str):
      	usedate = datetime.datetime.strptime(usedate_str, '%Y-%m-%d')
      	nextday_date = usedate + datetime.timedelta(days=1)
      	return nextday_date.strftime('%Y-%m-%d')
      
      def get_nextday_date(usedate):
      	nextday_date = usedate + datetime.timedelta(days=1)
      	return nextday_date
      
      def date_to_str(usedate):
      	return usedate.strftime('%Y-%m-%d')
      
      def get_valid_title(s):
      	return str(s).replace('...', '…')
      
      def get_valid_title_reverse(s):
      	return str(s).replace('…', '...')
      
      def get_valid_filename(s):
          s = str(s).replace('...', '').replace('…', '').replace(':', '.').strip().replace(' ', '_').replace('__', '_').replace(u'Ä', 'Ae').replace(u'Ö', 'Oe').replace(u'Ü', 'Ue').replace(u'ä', 'ae').replace(u'ö', 'oe').replace(u'ü', 'ue').replace(u'ß', 'ss')
          return re.sub(r'(?u)[^-\w.]', '', s)
      
      def build_legacy_filename(date, series, track, title, preacher):
      	date = get_valid_filename(date)
      	series = get_valid_filename(series)
      	track = get_valid_filename(track)
      	title = get_valid_filename(title)
      	preacher = get_valid_filename(preacher)
      
      	if mp3_default_series in series:
      		filename = date+'_'+title+'_('+preacher+').mp3'
      	else:
      		filename = date+'_'+series+'_['+track+']_'+title+'_('+preacher+').mp3'
      
      	return filename
      
      def build_filename(date, series, title, preacher):
      	date = get_valid_filename(date)
      	series = get_valid_filename(series)
      	title = get_valid_filename(title)
      	preacher = get_valid_filename(preacher)
      
      	filename = date+'_'+series+'_'+title+'_'+preacher+'.mp3'
      
      	return filename
      
      ### word press selenium login	
      def wp_selenium_logon(d):
      
      	l = d.find_element_by_xpath("//input[@id='user_login']")
      	if l:
      		l.send_keys(wp_user) 
      		d.find_element_by_xpath("//input[@id='user_pass']").send_keys(wp_password)
      		d.find_element_by_xpath("//input[@id='rememberme']").click()
      		d.find_element_by_xpath("//input[@id='wp-submit']").click()
      
      ## get a cookie from churchtools
      def set_ct_cookies():
      	if 'ct_cookies' not in globals():
      		login_payload = {'username': ct_username, 'password': ct_password}
      		r = requests.post(ct_url+'login', data=login_payload)
      		global ct_cookies
      		ct_cookies=r.cookies
      
      ## split description into series name and sermon title
      def ct_event_desc_to_sermon(desc):
      	result={}
      	if ct_sermon_tag in desc:
      		sermonline = desc[desc.rfind(ct_sermon_tag)+1:].strip()
      	else:
      		sermonline = desc.strip()
      
      
      	if sermonline.count(ct_series_sep) == 1:
      		series = sermonline.split(ct_series_sep)[0].strip()
      		sermon = sermonline.split(ct_series_sep)[1].split('\n')[0].strip()
      	else:
      		series = mp3_default_series
      		sermon = sermonline.split('\n')[0].strip()
      
      	result['series'] = series.replace('"', '')
      	result['sermon'] = sermon.replace('"', '')
      
      	return result
      
      def get_ct_events(events_from, events_to):
      	set_ct_cookies()
      	events_payload = {'from': events_from, 'to': events_to}
      	r = requests.get(ct_url+'events', cookies=ct_cookies, params=events_payload)
      	r_events = r.json()
      	return r_events['data']
      
      def concat_ct_preacher(event_id):
      	set_ct_cookies()
      	r = requests.get(ct_url+'events/'+str(event_id), cookies=ct_cookies)
      	r_event = r.json()
      	ct_preacher = ''
      	for ct_service in r_event['data']['eventServices']:
      		if ct_service['serviceId'] == ct_preacher_serviceid:
      			ct_preacher = ct_preacher+ct_service['name']+', '
      	return ct_preacher[:-2]
      
      
      
      def concat_wp_preacher(wp_preacher_id_list):
      	wp_preacher = ''
      	for wp_preacher_id in (wp_preacher_id_list):
      		r = requests.get(wp_rest_url+'wpfc_preacher/'+str(wp_preacher_id))
      		wp_preacher = wp_preacher+r.json()['name']+', '
      	if len(wp_preacher) > 0:
      		return wp_preacher[:-2]
      	else:
      		return ''
      
      def concat_wp_series(wp_series_id_list):
      	wp_series = ''
      	for wp_series_id in (wp_series_id_list):
      		r = requests.get(wp_rest_url+'wpfc_sermon_series/'+str(wp_series_id))
      		wp_series_name = wp_series+r.json()['name']
      		if wp_series_name[:2].isnumeric() and int(wp_series_name[:2]) >= 7 and int(wp_series_name[:2]) < 45 and wp_series_name[2:5] == ' - ':
      			wp_series_name = wp_series_name[5:]
      		wp_series = wp_series+wp_series_name+', '
      	if len(wp_series) > 0:
      		return wp_series[:-2]
      	else:
      		return ''
      
      ## get all sermon information from an event
      def ct_event_to_dict(event_data):
      	result = {}
      	event_id = event_data['id']
      	result[event_id] = {}
      	desc = event_data['description'].strip()
      	s = ct_event_desc_to_sermon(desc)
      	time = event_data['startDate']
      	result[event_id]['releasedate'] = time[:10]
      	result[event_id]['series'] = s['series']
      	result[event_id]['sermon'] = s['sermon']
      	result[event_id]['preacher'] = concat_ct_preacher(event_id)
      	result[event_id]['timeutc'] = time
      	result[event_id]['desc'] = desc
      	result[event_id]['caldomain'] = event_data['calendar']['domainIdentifier']
      	#result[event_id]['campus'] = event_data['calendar']['domainAttributes']['campusName']
      
      	return result
      	
      def valid_ct_event_to_dict(event_data):
      	if event_data['calendar']['domainIdentifier'] in ct_caldomains and event_data['description'].strip() not in ct_exclude_titles:
      		return ct_event_to_dict(event_data)
      
      def cloud_login(cloud_url, cloud_username, cloud_password):
      	cloud = owncloud.Client(cloud_url)
      	cloud.login(cloud_username, cloud_password)
      	return cloud
      
      def ftp_login():
      	global ftp
      	ftp = ftplib.FTP_TLS(ftp_host, ftp_username, ftp_password)
      	ftp.prot_p()
      	return ftp
      
      def count_remote_file(ftp):
      	if not ftp:
      		ftp = ftp_login()
      
      	remote_list = []
      	ftp.retrlines('LIST', remote_list.append)
      	i = 0
      	for rf in remote_list:
      		if '.mp3' in rf:
      			i+=1
      	return i
      
      def close_exit(mp3, ftp):
      		mp3.close()
      		ftp.quit()
      		sys.exit()
      
      
      def publish_sermon_ftp(file):
      	ftp = ftp_login()
      
      	if count_remote_file(ftp) > 0:
      		print("WARNING: The import directory has already mp3 files:")
      		ftp.dir()
      
      	mp3 = open(file,'rb')
      	print("Uploading '"+file+"' via FTPs to", ftp_host)
      
      	try:
      		ftp.storbinary('STOR '+file, mp3)
      	except:
      		print("ERROR: '"+file+"' could not be uploaded. Exiting")
      		close_exit(mp3, ftp)
      
      	print("Upload was successfull")
      	mp3.close()
      	ftp.quit()
      	
      
      def publish_sermon_cloud(file):
      	print("Uploading '"+file+"' via nextCloud to", cloud_url, "into the directory '"+cloud_upload_dir+"'")
      	cloud = cloud_login()
      	cloud.put_file(cloud_upload_dir+'/'+file, file)
      
      
      
      def download_mp3_from_cloud(cloud, remote_file, local_mp3_path, delete_from_cloud_on_ok):
      	print("Downloading '"+remote_file.get_path()+'/'+remote_file.get_name()+"' to '"+local_mp3_path+"'")
      	ok = cloud.get_file(remote_file, local_mp3_path)
      	if ok and delete_from_cloud_on_ok:
      		cloud.delete(remote_file)
      
      
      def get_mp3_from_cloud(cloud_download_dirs, yyyymmdd, delete_from_cloud_on_ok):
      	cloud = cloud_login(cloud_url, cloud_username, cloud_password)
      	local_mp3_path = None
      	for cloud_remote_dir in cloud_download_dirs:
      	#	print(cloud_remote_dir)
      		dir_files = cloud.list(cloud_remote_dir)
      	#	print(dir_files)
      		for remote_file in dir_files:
      			remote_file_ending = remote_file.get_name()[-4:]
      	#		print(remote_file_ending, yyyymmdd, str(remote_file))
      			if (yyyymmdd == 'all' or yyyymmdd in str(remote_file)) and remote_file_ending == '.mp3':
      				remote_file_name = remote_file.get_name()
      				remote_file_path = cloud_remote_dir+'/'+remote_file_name
      				local_mp3_name = remote_file_name.replace('.mp3', '')+cloud_remote_dir.replace('mp3_', '_')+'.mp3'
      				local_mp3_path = mp3_dir+'/'+local_mp3_name
      				download_mp3_from_cloud(cloud, remote_file, local_mp3_path, delete_from_cloud_on_ok)
      			if remote_file_ending in ['.HM0', '.HMP', '.VIP']:
      				cloud.delete(remote_file)
      
      	return local_mp3_path
      
      def build_youtube_url(yt_video_id):
      	if yt_video_id != None and yt_video_id != '' and len(yt_video_id)>3:
      		return 'https://www.youtube.com/watch?v='+yt_video_id
      	else:
      		return None
      
      def get_youtube_playlist_items():
      	yt_url_playlist = yt_url+'playlistItems?key='+yt_auth_key+'&part=contentDetails&order=date&playlistId='+yt_playlist_id+'&channelId='+yt_channel_id+'&maxResults='+yt_max_playlist_results
      	r = requests.get(yt_url_playlist)
      	return r.json()
      
      def get_youtube_playlist_video_id(yt_playlist_items, checkdate):
      	yt_video_id = None
      	for pl_item in yt_playlist_items['items']:
      		if checkdate in pl_item['contentDetails']['videoPublishedAt']:
      			yt_video_id = pl_item['contentDetails']['videoId']
      			break
      	return yt_video_id
      
      
      def get_youtube_video_id(from_date, to_date):
      
      	yt_video_id = None
      
      	yt_search_url = yt_url+'search?key='+yt_auth_key+'&type=video&order=date&channelId='+yt_channel_id+'&maxResults='+yt_max_search_results+'&publishedAfter='+from_date+'T00:00:00Z&publishedBefore='+to_date+'T00:00:00Z'
      	# print(yt_search_url)
      	r = requests.get(yt_search_url)
      	date_videos = r.json()
      
      	if date_videos['pageInfo']['totalResults'] == 1:
      		for date_video in date_videos['items']:
      			yt_video_id = date_video['id']['videoId']
      
      	if yt_video_id == None:
      		yt_playlist_items = get_youtube_playlist_items()
      
      		for date_video in date_videos['items']:
      			if yt_video_id != None:
      				break
      			else:
      				for pl_item in yt_playlist_items['items']:
      					if yt_video_id != None:
      						break
      					else:
      						if date_video['id']['videoId'] == pl_item['contentDetails']['videoId']:
      							yt_video_id = date_video['id']['videoId']
      
      	return yt_video_id
      
      
      def get_youtube_url(from_date, to_date):
      	yt_video_id = get_youtube_video_id(from_date, to_date)
      	if yt_video_id != None:
      		return build_youtube_url(yt_video_id)
      	else:
      		return None
      
      def check_wp_sermon_published(sermon_title):
      	found = False
      	r = requests.get(wp_rest_url+'wpfc_sermon')
      	wp_sermons = r.json()
      	for wp_sermon in wp_sermons:
      		if sermon_title == wp_sermon['title']['rendered']:
      			found = True
      			print("The sermon '"+sermon_title+"' is already published.")
      
      	return found
      
      def build_wp_sermon_desc(date_series, date_preacher, youtube_video_url):
      	wp_sermon_desc = ''
      	if (date_series == mp3_default_series or date_series == '' or date_series == None) and date_preacher != None and date_preacher != '' and youtube_video_url == None:
      		wp_sermon_desc = date_preacher
      	elif (date_series == mp3_default_series or date_series == '' or date_series == None) and date_preacher != None and date_preacher != '' and youtube_video_url != None:
      		wp_sermon_desc = date_preacher+" <br />\r\n| <a href=\""+youtube_video_url+"\" rel=\"noopener\" target=\"_blank\">"+youtube_video_url+"</a> |"
      	elif date_series != mp3_default_series and date_series != '' and date_series != None and date_preacher != None and date_preacher != '' and youtube_video_url == None:
      		wp_sermon_desc = date_series+" | "+date_preacher
      	elif date_series != mp3_default_series and date_series != '' and date_series != None and date_preacher != None and date_preacher != '' and youtube_video_url != None:
      		wp_sermon_desc = date_series+" | "+date_preacher+" <br />\r\n| <a href=\""+youtube_video_url+"\" rel=\"noopener\" target=\"_blank\">"+youtube_video_url+"</a> |"
      	else:
      	return wp_sermon_desc
      
      
      def rename_mp3file(mp3file, newfilename):
      	if mp3file != newfilename:
      		print("Renaming '"+mp3file+"' to '"+newfilename+"'")
      		os.rename(mp3file, newfilename)
      	return newfilename
      
      
      def tag_mp3file(mp3file, artist, title, album, year, track_num, release_date):
      
      	mp3 = eyed3.load(mp3file)
      	if 'NoneType' not in str(type(mp3.tag)):
      		mp3.tag.remove(mp3file)
      		mp3.tag.save()
      		mp3.tag.clear()
      		mp3 = eyed3.load(mp3file)
      	mp3.initTag()
      	mp3.tag.artist = artist
      	mp3.tag.title = title
      	mp3.tag.album = album
      	mp3.tag.year = year
      	mp3.tag.track_num = track_num
      	mp3.tag.release_date = release_date
      	mp3.tag.original_release_date = release_date
      	mp3.tag.recording_date = release_date
      	mp3.tag.tagging_date = release_date
      	mp3.tag.album_artist = mp3_albumartist
      	mp3.tag.genre = mp3_genre
      	mp3.tag.publisher = mp3_publisher
      	mp3.tag.composer = mp3_composer
      	mp3.tag.publisher_url = mp3_composer
      	mp3.tag.internet_radio_url = mp3_url_apple
      	img = open(mp3_cover,'rb').read()
      	mp3.tag.images.set(3, img, 'image/jpeg', mp3_publisher)
      
      	mp3.tag.save(version=eyed3.id3.ID3_DEFAULT_VERSION, encoding='utf-8')
      	
      	print('Recognized and applied MP3 tags:')
      	print("{}\t{}\t{}\t".format("", "Date:          ", mp3.tag.release_date))
      	print("{}\t{}\t{}\t".format("", "Album:         ", mp3.tag.album))
      	print("{}\t{}\t{}\t".format("", "Track number:  ", mp3.tag.track_num))
      	print("{}\t{}\t{}\t".format("", "Title:         ", mp3.tag.title))
      	print("{}\t{}\t{}\t".format("", "Preacher:      ", mp3.tag.artist))
      	print("{}\t{}\t{}\t".format("", "File name:     ", mp3file))
      
      
      def update_chromedriver():
      	# get local ver
      	with open(driver_version_file, "r") as f:
      		local_driver_version = f.read().replace("\n", "")
      
      	# get remote ver
      	r = requests.get(driver_url+'LATEST_RELEASE')
      	remote_driver_version = r.text
      
      	# compare vers
      	if remote_driver_version > local_driver_version:
      		print("chromedriver will be updated from '"+local_driver_version+"' to '"+remote_driver_version+"'")
      
      		# move old ver to archive
      		os.rename(cloud_chromedriver_path, cloud_local_dir+'/scripts/archive/chromedriver_'+local_driver_version)
      
      		# get the new ver zip
      		r = requests.get(driver_url + remote_driver_version + '/' + driver_zip)
      		open(cloud_local_dir+'/scripts/archive/'+driver_zip, 'wb').write(r.content)
      		with zipfile.ZipFile(cloud_local_dir+'/scripts/archive/'+driver_zip, 'r') as zip_ref:
      		   	zip_ref.extractall(cloud_local_dir+'/scripts')
      		# set permissions
      		os.chmod(cloud_chromedriver_path, 0o775)
      
      		# set new version as local
      		with open(driver_version_file, "w") as f:
      			f.write(remote_driver_version)
      
      
      def publish_sermon_wp_selenium(mp3file, published, sermon_title, youtube_video_url, description):
      	if youtube_video_url != None:
      		print('Youtube Video URL: '+youtube_video_url)
      	print('Sermon description: '+description)
      	update_chromedriver()	
      	global d
      	o = Options()
      	o.add_argument("--disable-infobars")
      	d = webdriver.Chrome(cloud_chromedriver_path, options=o)
      
      	if not published:
      		### Open 'Import Sermons'
      		d.get(wp_url_import)
      		d.implicitly_wait(3)
      		wp_selenium_logon(d)
      		d.implicitly_wait(3)
      		### 'Details' button
      		d.find_element_by_xpath("//button[@id='details-"+mp3file.replace('.', '_')+"']").click()
      		d.implicitly_wait(30)
      		### import button 'Daten importieren'
      		d.find_element_by_xpath("//input[@name='"+mp3file+"']").click()
      		d.implicitly_wait(10)
      		### Open 'Alle Predigten'
      		#d.find_element_by_xpath("//a[@href='"+mp3file+"']").click()
      		#d.implicitly_wait(3)
      		d.get(wp_url_sermons)
      		d.implicitly_wait(3)
      	else:
      		### Open 'Alle Predigten'
      		d.get(wp_url_sermons)
      		d.implicitly_wait(3)
      		wp_selenium_logon(d)
      	### Open currect sermon for editing
      	d.find_element_by_link_text(sermon_title).click()
      	### Update embeded youtube video
      	if youtube_video_url != None:
      		v = d.find_element_by_xpath("//input[@id='sermon_video_link']")
      		v.clear()
      		v.send_keys(youtube_video_url)
      
      	### Update the description in Sermon Manger Pro
      	#c = d.find_element_by_xpath("//textarea[@name='content']")
      	### Update the description in Sermon Manager free version
      	c = d.find_element_by_xpath("//textarea[@id='sermon_description']")
      	c.clear()
      	c.send_keys(description)
      	### Press button 'Aktualisieren'
      	#d.find_element_by_xpath("//input[@id='publish']").click()
      	e = d.find_element_by_xpath("//input[@id='publish']")
      	d.execute_script("arguments[0].click();", e)
      
      	### Show updated sermon
      	d.implicitly_wait(3)
      	d.find_element_by_link_text('Predigt ansehen').click()
      
      
      def main():
      	######################################################
      	#        SCRIPT BODY
      	######################################################
      
      	args = get_args()
      
      	if args.mp3file:
      		mp3file_path = args.mp3file
      		mp3file = os.path.basename(args.mp3file_path)
      		usedate = datetime.datetime.strptime(mp3file[:10], '%Y-%m-%d')
      		sermondate = usedate
      	elif args.date:
      		usedate = datetime.datetime.strptime(args.date, '%Y-%m-%d')
      		sermondate = usedate
      	else:
      		usedate = date.today()
      		# check if it's Sunday. If not use last Sunday before this date
      		offset = (usedate.weekday() - 6) % 7
      		sermondate = usedate - timedelta(days=offset)
      
      	lookback_days = args.lookbackdays
      	if args.single:
      		lookback_days = 1
      
      
      
      	fromdate = sermondate - datetime.timedelta(days=lookback_days)
      	# "Monday" after the sermon date
      	nextday = sermondate + datetime.timedelta(days=1)
      	#checktime = sermondate.strftime('%Y-%m-%dT08:00:00Z')
      	checkdate = sermondate.strftime('%Y-%m-%d')
      	lookbackdate = fromdate.strftime('%Y-%m-%d')
      	events_to = nextday.strftime('%Y-%m-%d')
      
      
      
      	if args.quiet:
      		go='y'
      	else:
      		go=''
      
      	if args.remotemp3:
      		mp3_found = get_mp3_from_cloud(cloud_download_dirs, checkdate, True)
      		if mp3_found == None:
      			sys.exit("No MP3 could be found on the cloud")
      
      	while go not in ['y', 'n']:
      		go = input("Open Audacity and apply the 'Clean Speech' Macro to the downloaded MP3. Then enter 'y' (yes) to continue or 'n' to stop the script\nShould I continue with tagging? [y/n]: ")
      
      	if go == 'n':
      		sys.exit("Exiting on user demand")
      
      	os.chdir(mp3_wdir)
      	mp3_list = glob.glob(str(checkdate)+"*.mp3")
      
      	if len(mp3_list) > 0:
      		mp3file = mp3_list[0]
      	else:
      		mp3file = mp3_list
      
      	print("Using '"+mp3file+"' for further processing")
      
      	if args.church in 'GT':
      		ct_caldomains = ct_caldomains_gt
      	else:
      		ct_caldomains = ct_caldomains_bi
      
      
      	### get event of the sermon for the correct time and church domain/location/campus (Bielefeld vs. Guetersloh)
      
      	date_releasedate = None
      	date_series = None
      	date_sermon = None 
      	date_preacher = None
      	
      	date_events = get_ct_events(checkdate, events_to)
      	for event in date_events:
      		date_event = valid_ct_event_to_dict(event)
      		if date_event != None:
      			for date_event_id in date_event:
      				date_releasedate = date_event[date_event_id]['releasedate']
      				date_series = date_event[date_event_id]['series']
      				date_sermon = date_event[date_event_id]['sermon']
      				date_preacher = date_event[date_event_id]['preacher']
      		
      		if date_releasedate == '' or date_releasedate == None:
      			date_releasedate = checkdate
      		if date_series == '' or date_series == None:
      			date_series = mp3_default_series
      		if date_sermon == '' or date_sermon == None:
      			date_sermon = input('Sermon title [Predigt vom '+checkdate+']:')
      			if date_sermon == '' or date_sermon == None:
      				date_sermon = 'Predigt vom '+checkdate
      		if date_preacher == '' or date_preacher == None:
      			date_preacher = input('Preacher ['+mp3_default_preacher+']:')
      			if date_preacher == '' or date_preacher == None:
      				date_preacher = mp3_default_preacher
      
      	# remove chars with different interpretaion in wordpress:
      	date_sermon = get_valid_title(date_sermon)
      	date_series = get_valid_title(date_series)
      
      	if date_series not in mp3_default_series:
      		event_id = ''
      		allevents = {}
      
      		events = get_ct_events(lookbackdate, events_to)
      
      		for event in events:
      			line = valid_ct_event_to_dict(event)
      			if line != None:
      				allevents.update(line)
      
      		i=0
      		series_sermons = []
      		for event in allevents:
      			if allevents[event]['series'] == get_valid_title_reverse(date_series) and allevents[event]['sermon'] not in series_sermons:
      				series_sermons.append(allevents[event]['sermon'])
      		i = len(series_sermons)
      		filename_sermon = date_sermon
      		date_sermon = '('+str(i)+') '+date_sermon
      		date_track_num = str(i)
      	else:
      		date_track_num = date_releasedate[5:7]+date_releasedate[8:10]
      		filename_sermon = date_sermon
      
      
      	
      	if 'mp3file' in locals():
      		mp3file = rename_mp3file(mp3file, build_filename(date_releasedate, date_series, date_sermon, date_preacher))
      		tag_mp3file(mp3file, date_preacher, date_sermon, date_releasedate[2:4]+' - '+date_series, date_releasedate[:4], date_track_num, date_releasedate)
      		youtube_video_url = get_youtube_url(str(checkdate), str(events_to))
      		published = check_wp_sermon_published(date_sermon)
      
      		if args.quiet:
      			go='y'
      		else:
      			go=''
      
      		while go not in ['y', 'n']:
      			go = input("Should I continue with upload and publishing? [y/n]: ")
      
      		if go == 'n':
      			sys.exit("Exiting on user demand")
      
      		if args.publish and not published and not args.nextcloud:
      			publish_sermon_ftp(mp3file)
      		elif args.publish and not published and args.nextcloud:
      			publish_sermon_cloud(mp3file)
      
      		if args.publish: 
      			publish_sermon_wp_selenium(mp3file, published, date_sermon, youtube_video_url, build_wp_sermon_desc(date_series, date_preacher, youtube_video_url))
      
      if __name__ == '__main__':
      	main()
      
      
      
      
      B 1 Antwort Letzte Antwort Antworten Zitieren 2
      • B
        bwl21 @Andreas B
        zuletzt editiert von bwl21

        @andreas-b Interessanter Beitrag vielen Dank.

        Da schildere ich mal, wie wir das machen:

        • Veranstaltungen werden in Churchtools gepflegt, und nur dort.

        • im Info-Feld der Veranstaltung stehen Tags mit Meta-Informationen:

          dcf5f8db-4b1e-4040-9ab4-a62da4c7f840-image.png

        • Im Ablauf gibt es einen Eintrag "info-fuer-homepage". Dort steht in Markdown der Text, der auf die Homepage soll

          67306bef-e621-46f7-989f-efd4db1c44d8-image.png

        • Da wir eine gewisse Volatilität in den Details haben, wird einmal pro Stunde CT mit der Homepage synchronisiert (über das API unseres CMS). Dabei werden die "Tags", der Ablauf, und die Dienste von CT sowie der Kalender, verarbeitet. Auch die Steuerung von Livestreameinbettung und Anmeldesystem wird da befüttert.

        • Am Ende sieht das dann so aus

        • Wir streamen über Twitch. Nach der Veranstaltung schneiden wir ein Highlight und importieren die Links automatisch auf die Homepage.

        Um den Technologiestack nicht zu weit zu treiben, läuft das alles mit PHP (obwohl ich lieber Ruby oder sowas hätte).

        AndyA 1 Antwort Letzte Antwort Antworten Zitieren 1
        • AndyA
          Andy admin @bwl21
          zuletzt editiert von

          @bwl21 sagte in Prozess und Python Skript für Automatisierung der MP3/Podcast-Veröffentlichung:

          Am Ende sieht das dann so aus

          der Link funktioniert bei mir nicht ...

          B 1 Antwort Letzte Antwort Antworten Zitieren 0
          • B
            bwl21 @Andy
            zuletzt editiert von bwl21

            @andy echt jetzt ... bei mir tut das. Was passiert da bei dir?

            Der Anmeldelink zu diese Veranstaltung ist abgelaufen, da hab ich schon ein Ticket für.

            Probier mal hier, da ist zwar kein Text mehr drin, aber dafür eine Anmeldung

            https://www.bruedergemeinde-korntal.de/neuigkeiten/termine/kalender-detail/CT_1995.html

            AndyA 1 Antwort Letzte Antwort Antworten Zitieren 0
            • AndyA
              Andy admin @bwl21
              zuletzt editiert von

              @bwl21 jetzt gehen beide. Eben kam "Seite wurde nicht gefunden".

              1 Antwort Letzte Antwort Antworten Zitieren 0
              • Erster Beitrag
                Letzter Beitrag