def test_podcast_duplicates(self): # make sure duplicate name, or archive type and broadcast id not allowed with utils.temp_podcast(self.client) as podcast1: with utils.temp_dir() as temp_dir: with self.assertRaises(HathorException) as error: self.client.podcast_create(podcast1['archive_type'], podcast1['broadcast_id'] + '1', podcast1['name'], file_location=temp_dir) self.check_error_message('Cannot create podcast, name was %s' % podcast1['name'], error) with self.assertRaises(HathorException) as error: self.client.podcast_create(podcast1['archive_type'], podcast1['broadcast_id'], podcast1['name'] + 's', file_location=temp_dir) self.check_error_message('Cannot create podcast, name was %ss' % podcast1['name'], error) # also check updating fails an existing one to one that exists fails with utils.temp_podcast(self.client) as podcast2: with self.assertRaises(HathorException) as error: self.client.podcast_update(podcast1['id'], podcast_name=podcast2['name']) self.check_error_message('Cannot update podcast id:%s' % podcast1['id'], error) # also check updating fails an existing one to one that exists fails with utils.temp_podcast(self.client) as podcast2: with self.assertRaises(HathorException) as error: self.client.podcast_update(podcast1['id'], podcast_name=podcast2['name']) self.check_error_message('Cannot update podcast id:%s' % podcast1['id'], error) with self.assertRaises(HathorException) as error: self.client.podcast_update(podcast1['id'], broadcast_id=podcast2['broadcast_id']) self.check_error_message('Cannot update podcast id:%s' % podcast1['id'], error)
def test_podcast_multiple_crud(self): # check multiple outputs on show and delete with utils.temp_podcast(self.client, delete=False) as podcast1: with utils.temp_podcast(self.client, delete=False) as podcast2: podcasts = self.client.podcast_show([podcast1['id'], podcast2['id']]) self.assert_length(podcasts, 2) self.client.podcast_delete([podcasts[0]['id'], podcasts[1]['id']]) pod_list = self.client.podcast_list() self.assert_length(pod_list, 0)
def test_podcast_update_archive_type(self): with self.assertRaises(HathorException) as error: with utils.temp_podcast(self.client, archive_type='foo') as podcast: pass self.check_error_message('Archive Type must be in accepted list of keys - foo value given', error) with utils.temp_podcast(self.client) as podcast: self.client.podcast_update(podcast['id'], archive_type='soundcloud') with self.assertRaises(HathorException) as error: self.client.podcast_update(podcast['id'], archive_type='bar') self.check_error_message('Archive Type must be in accepted list - bar value given', error)
def test_episode_download_remove_commercial_with_picture(self): # curl download used for rss and soundcloud pod_args = {"archive_type": "rss", "max_allowed": 1, "remove_commercials": True} with test_utils.temp_podcast(self.client, broadcast_url=True, **pod_args) as podcast: httpretty.register_uri(httpretty.GET, podcast["broadcast_id"], body=history_on_fire.DATA) self.client.episode_sync() episode_list = self.client.episode_list(only_files=False) with test_utils.temp_audio_file(open_data=False) as mp3_file: with test_utils.temp_image_file() as image_file: metadata.picture_update(mp3_file, image_file) with open(mp3_file, "r") as f: mp3_body = f.read() test_utils.mock_mp3_download(episode_list[0]["download_url"], mp3_body) self.client.episode_download(episode_list[0]["id"]) episode = self.client.episode_show(episode_list[0]["id"])[0] self.assert_not_none(episode["file_path"]) # make sure episode list shows episode with only_files=True episode_list = self.client.episode_list() self.assert_length(episode_list, 1) self.assert_not_none(episode_list[0]["file_size"]) self.assertTrue(episode_list[0]["file_size"] > 0) # make sure image file is right with utils.temp_file(suffix=".jpg") as temper: metadata.picture_extract(episode_list[0]["file_path"], temper) with open(temper, "r") as f: with open(image_file, "r") as ff: self.assertEqual(f.read(), ff.read())
def test_podcast_file_sync(self): # download only one podcast episode with utils.temp_podcast(self.client, archive_type='soundcloud', max_allowed=1) as podcast: url = urls.soundcloud_track_list(podcast['broadcast_id'], self.client.soundcloud_client_id) httpretty.register_uri(httpretty.GET, url, body=json.dumps(soundcloud_one_track.DATA)) self.client.episode_sync() episode_list = self.client.episode_list(only_files=False) with utils.temp_audio_file() as mp3_body: utils.mock_mp3_download(episode_list[0]['download_url'], mp3_body) self.client.podcast_file_sync() episode_list = self.client.episode_list() self.assert_not_none(episode_list[0]['file_path']) first_episode_date = episode_list[0]['date'] # add an additional, newer podcast, make sure things are deleted url = urls.soundcloud_track_list(podcast['broadcast_id'], self.client.soundcloud_client_id) httpretty.register_uri(httpretty.GET, url, body=json.dumps(soundcloud_two_tracks.DATA)) self.client.episode_sync() episode_list = self.client.episode_list(only_files=False) with utils.temp_audio_file() as mp3_body: utils.mock_mp3_download(episode_list[1]['download_url'], mp3_body) self.client.podcast_file_sync() # make sure 2 episodes in db, but only 1 with a file path episode_list = self.client.episode_list() self.assert_not_none(episode_list[0]['file_path']) all_episodes = self.client.episode_list(only_files=False) self.assertNotEqual(len(episode_list), len(all_episodes)) second_episode_date = episode_list[0]['date'] self.assertTrue(datetime.strptime(second_episode_date, self.client.datetime_output_format) > datetime.strptime(first_episode_date, self.client.datetime_output_format))
def test_podcast_file_sync_exclude(self): # create two podcasts, exclude one, make sure only that pod was updated with utils.temp_podcast(self.client, archive_type='soundcloud', max_allowed=1) as podcast1: url = urls.soundcloud_track_list(podcast1['broadcast_id'], self.client.soundcloud_client_id) httpretty.register_uri(httpretty.GET, url, body=json.dumps(soundcloud_one_track.DATA)) self.client.episode_sync() episode_list = self.client.episode_list(only_files=False) with utils.temp_audio_file() as mp3_body: utils.mock_mp3_download(episode_list[0]['download_url'], mp3_body) with utils.temp_podcast(self.client) as podcast2: self.client.podcast_file_sync(exclude_podcasts=[podcast2['id']], ) episode_list = self.client.episode_list() self.assertTrue(len(episode_list) > 0) for episode in episode_list: self.assertEqual(podcast1['id'], episode['podcast_id'])
def test_episode_prevent_deletion(self): # download only one podcast episode with test_utils.temp_podcast(self.client, archive_type="soundcloud", max_allowed=1) as podcast: url = urls.soundcloud_track_list(podcast["broadcast_id"], self.client.soundcloud_client_id) httpretty.register_uri(httpretty.GET, url, body=json.dumps(soundcloud_one_track.DATA)) self.client.episode_sync() episode_list = self.client.episode_list(only_files=False) with test_utils.temp_audio_file() as mp3_body: test_utils.mock_mp3_download(episode_list[0]["download_url"], mp3_body) self.client.podcast_file_sync() # mark episode to prevent deletion self.client.episode_update(episode_list[0]["id"], prevent_delete=True) # add an additional, newer podcast, make sure prevented deletion episode stays url = urls.soundcloud_track_list(podcast["broadcast_id"], self.client.soundcloud_client_id) httpretty.register_uri(httpretty.GET, url, body=json.dumps(soundcloud_three_tracks.DATA)) self.client.episode_sync(max_episode_sync=0) episode_list = self.client.episode_list(only_files=False) test_utils.mock_mp3_download(episode_list[1]["download_url"], mp3_body) test_utils.mock_mp3_download(episode_list[2]["download_url"], mp3_body) self.client.podcast_file_sync() episode_list = self.client.episode_list() ep_ids = [i["id"] for i in episode_list] self.assertTrue(2 in ep_ids) self.assertTrue(1 in ep_ids) self.assertTrue(3 not in ep_ids)
def test_podcast_location_update(self): # check fails with invalid data with self.assertRaises(HathorException) as error: self.client.podcast_update_file_location(1, 'foo') self.check_error_message('Podcast not found for ID:1', error) # check works with valid data with utils.temp_podcast(self.client, archive_type='rss', broadcast_url=True, max_allowed=2) as podcast: httpretty.register_uri(httpretty.GET, podcast['broadcast_id'], body=history_on_fire.DATA) self.client.episode_sync() episode_list = self.client.episode_list(only_files=False) with utils.temp_audio_file() as mp3_body: utils.mock_mp3_download(episode_list[0]['download_url'], mp3_body) self.client.episode_download(episode_list[0]['id']) old_episode = self.client.episode_show(episode_list[0]['id'])[0] with utils.temp_dir(delete=False) as temp: self.client.podcast_update_file_location(podcast['id'], temp) # make sure episode path changed new_episode = self.client.episode_show(episode_list[0]['id'])[0] self.assertTrue(new_episode['file_path'].startswith(temp)) self.assertNotEqual(old_episode['file_path'], new_episode['file_path']) # make sure podcast path changed new_podcast = self.client.podcast_show(podcast['id'])[0] self.assertNotEqual(podcast['file_location'], new_podcast['file_location'])
def test_remove_commercial_values(self): # make sure remove commercial values are set correctly # .. upon creation and updates with self.assertRaises(HathorException) as error: with utils.temp_podcast(self.client, remove_commercials='foo'): pass self.check_error_message('Remove commercials must be boolean type - str type given', error) with utils.temp_podcast(self.client, remove_commercials=True) as podcast: self.assertEqual(podcast['remove_commercial'], True) self.client.podcast_update(podcast['id'], remove_commercials=None) podcast = self.client.podcast_show(podcast['id'])[0] self.assertEqual(podcast['remove_commercial'], True) self.client.podcast_update(podcast['id'], remove_commercials=False) podcast = self.client.podcast_show(podcast['id'])[0] self.assertEqual(podcast['remove_commercial'], False)
def test_episode_list_exclude_podcast_filter(self): with test_utils.temp_podcast(self.client, archive_type="rss", broadcast_url=True) as podcast1: httpretty.register_uri(httpretty.GET, podcast1["broadcast_id"], body=history_on_fire.DATA) with test_utils.temp_podcast(self.client, archive_type="soundcloud", max_allowed=2) as podcast2: page1_url = urls.soundcloud_track_list(podcast2["broadcast_id"], self.client.soundcloud_client_id) httpretty.register_uri( httpretty.GET, page1_url, body=json.dumps(soundcloud_archive_page1.DATA), content_type="application/json", ) self.client.episode_sync() episode_list_all = self.client.episode_list(only_files=False) episode_list_exc = self.client.episode_list(only_files=False, exclude_podcasts=[podcast2["id"]]) self.assertNotEqual(len(episode_list_all), len(episode_list_exc)) for episode in episode_list_exc: self.assertEqual(episode["podcast_id"], podcast1["id"])
def test_episode_list_with_sort_date(self): with test_utils.temp_podcast(self.client, archive_type="rss", broadcast_url=True) as podcast: httpretty.register_uri(httpretty.GET, podcast["broadcast_id"], body=history_on_fire.DATA) self.client.episode_sync() episode_list = self.client.episode_list(only_files=False, sort_date=True) # assume sql isnt totally borked, just make sure first is ahead of last date1 = datetime.strptime(episode_list[0]["date"], test_utils.DATETIME_FORMAT) date2 = datetime.strptime(episode_list[-1]["date"], test_utils.DATETIME_FORMAT) self.assertTrue(date1 > date2)
def test_episode_sync_exits_on_maximum(self): with test_utils.temp_podcast(self.client, archive_type="youtube", max_allowed=1) as podcast: url1 = urls.youtube_channel_get(podcast["broadcast_id"], self.client.google_api_key) with mock.patch("youtube_dl.YoutubeDL", side_effect=test_utils.youtube_mock): httpretty.register_uri( httpretty.GET, url1, body=json.dumps(youtube_archive1.DATA), content_type="application/json" ) self.client.episode_sync() episode_list = self.client.episode_list(only_files=False) self.assert_length(episode_list, 1)
def test_podcast_max_allowed_valid_values(self): # must be positive int with self.assertRaises(HathorException) as error: with utils.temp_podcast(self.client, max_allowed=0): pass self.check_error_message('Max allowed must be positive integer, 0 given', error) with utils.temp_podcast(self.client, max_allowed=2) as podcast: # make sure negative numbers are invalid with self.assertRaises(HathorException) as error: self.client.podcast_update(podcast['id'], max_allowed=-1) self.check_error_message('Max allowed must be positive integer or 0', error) # check update works as expected self.client.podcast_update(podcast['id'], max_allowed=0) podcast = self.client.podcast_show(podcast['id'])[0] self.assertEqual(podcast['max_allowed'], None) self.client.podcast_update(podcast['id'], max_allowed=3) podcast = self.client.podcast_show(podcast['id'])[0] self.assertEqual(podcast['max_allowed'], 3)
def test_podcast_file_sync_no_automatic_episode_download(self): # make sure no max allowed downloads all possible podcasts with utils.temp_podcast(self.client, archive_type='soundcloud', max_allowed=None, automatic_download=False) as podcast: url = urls.soundcloud_track_list(podcast['broadcast_id'], self.client.soundcloud_client_id) httpretty.register_uri(httpretty.GET, url, body=json.dumps(soundcloud_one_track_only_page.DATA)) self.client.episode_sync() episode_list = self.client.episode_list(only_files=False) with utils.temp_audio_file() as mp3_body: utils.mock_mp3_download(episode_list[0]['download_url'], mp3_body) self.client.podcast_file_sync() episode_list = self.client.episode_list() self.assert_length(episode_list, 0)
def test_episode_sync_soundcloud_max_allowed(self): # make sure you only get the one page from soundcloud pagination with test_utils.temp_podcast(self.client, archive_type="soundcloud", max_allowed=2) as podcast: page1_url = urls.soundcloud_track_list(podcast["broadcast_id"], self.client.soundcloud_client_id) httpretty.register_uri( httpretty.GET, page1_url, body=json.dumps(soundcloud_archive_page1.DATA), content_type="application/json", ) self.client.episode_sync() episode_list = self.client.episode_list(only_files=False) self.assertEqual(len(episode_list), 2)
def test_episode_delete(self): with test_utils.temp_podcast(self.client, archive_type="rss", broadcast_url=True) as podcast: httpretty.register_uri(httpretty.GET, podcast["broadcast_id"], body=history_on_fire.DATA) self.client.episode_sync() episode_list = self.client.episode_list(only_files=False) with test_utils.temp_audio_file() as mp3_body: test_utils.mock_mp3_download(episode_list[0]["download_url"], mp3_body) self.client.episode_download(episode_list[0]["id"]) episode = self.client.episode_show(episode_list[0]["id"])[0] self.assert_not_none(episode["file_path"]) self.client.episode_delete(episode_list[0]["id"]) # make sure actually deleted self.assert_length(self.client.episode_list(), 0)
def test_episode_download_curl(self): # curl download used for rss and soundcloud with test_utils.temp_podcast(self.client, archive_type="rss", broadcast_url=True) as podcast: httpretty.register_uri(httpretty.GET, podcast["broadcast_id"], body=history_on_fire.DATA) self.client.episode_sync() episode_list = self.client.episode_list(only_files=False) with test_utils.temp_audio_file() as mp3_body: test_utils.mock_mp3_download(episode_list[0]["download_url"], mp3_body) self.client.episode_download(episode_list[0]["id"]) episode = self.client.episode_show(episode_list[0]["id"])[0] self.assert_not_none(episode["file_path"]) # make sure episode list shows episode with only_files=True episode_list = self.client.episode_list() self.assert_length(episode_list, 1)
def test_podcast_basic_crud(self): # test create, list, show, and delete with utils.temp_podcast(self.client) as podcast: self.assert_dictionary(podcast, skip=['max_allowed', 'artist_name']) podcast_list = self.client.podcast_list() self.assert_length(podcast_list, 1) with self.assertRaises(HathorException) as error: self.client.podcast_show(['foo']) self.check_error_message('Input must be int type, foo given', error) with self.assertRaises(HathorException) as error: self.client.podcast_update(podcast['id'] + 1) self.check_error_message('Podcast not found for ID:%s' % (podcast['id'] + 1), error)
def test_episode_passes_title_filters(self): with test_utils.temp_podcast(self.client, archive_type="youtube", max_allowed=1) as podcast: url1 = urls.youtube_channel_get(podcast["broadcast_id"], self.client.google_api_key) episode_title = youtube_archive1.DATA["items"][-1]["snippet"]["title"] first_item_title_regex = "^%s" % episode_title self.client.podcast_title_filter_create(podcast["id"], first_item_title_regex) with mock.patch("youtube_dl.YoutubeDL", side_effect=test_utils.youtube_mock): httpretty.register_uri( httpretty.GET, url1, body=json.dumps(youtube_archive1.DATA), content_type="application/json" ) self.client.episode_sync() episode_list = self.client.episode_list(only_files=False) self.assert_length(episode_list, 1) self.assertEqual(episode_title, episode_list[0]["title"])
def test_podcast_dont_delete_episode_files(self): with utils.temp_podcast(self.client, archive_type='soundcloud', max_allowed=1) as podcast: url = urls.soundcloud_track_list(podcast['broadcast_id'], self.client.soundcloud_client_id) httpretty.register_uri(httpretty.GET, url, body=json.dumps(soundcloud_one_track.DATA)) self.client.episode_sync() episode_list = self.client.episode_list(only_files=False) with utils.temp_audio_file() as mp3_body: utils.mock_mp3_download(episode_list[0]['download_url'], mp3_body) self.client.podcast_file_sync() episode_list = self.client.episode_list() # delete and make sure file is still there self.client.podcast_delete(podcast['id'], delete_files=False) self.assertTrue(len(os.listdir(podcast['file_location'])) > 0) os.remove(episode_list[0]['file_path']) os.rmdir(podcast['file_location'])
def test_episode_download_remove_commercial(self): # curl download used for rss and soundcloud pod_args = {"archive_type": "rss", "max_allowed": 1, "remove_commercials": True} with test_utils.temp_podcast(self.client, broadcast_url=True, **pod_args) as podcast: httpretty.register_uri(httpretty.GET, podcast["broadcast_id"], body=history_on_fire.DATA) self.client.episode_sync() episode_list = self.client.episode_list(only_files=False) with test_utils.temp_audio_file() as mp3_body: test_utils.mock_mp3_download(episode_list[0]["download_url"], mp3_body) self.client.episode_download(episode_list[0]["id"]) episode = self.client.episode_show(episode_list[0]["id"])[0] self.assert_not_none(episode["file_path"]) # make sure episode list shows episode with only_files=True episode_list = self.client.episode_list() self.assert_length(episode_list, 1) self.assert_not_none(episode_list[0]["file_size"]) self.assertTrue(episode_list[0]["file_size"] > 0)
def test_episode_delete_file(self): # check works with valid input with test_utils.temp_podcast(self.client, archive_type="rss", broadcast_url=True) as podcast: httpretty.register_uri(httpretty.GET, podcast["broadcast_id"], body=history_on_fire.DATA) self.client.episode_sync() episode_list = self.client.episode_list(only_files=False) with test_utils.temp_audio_file() as mp3_body: test_utils.mock_mp3_download(episode_list[0]["download_url"], mp3_body) self.client.episode_download(episode_list[0]["id"]) # make sure file exists episode = self.client.episode_show(episode_list[0]["id"])[0] self.assert_not_none(episode["file_path"]) # delete episode file, but not episode self.client.episode_delete_file(episode_list[0]["id"]) episode = self.client.episode_show(episode_list[0]["id"])[0] self.assert_none(episode["file_path"]) self.assert_none(episode["file_size"])
def test_podcast_database_cleanup(self): # download only one podcast episode with test_utils.temp_podcast(self.client, archive_type="soundcloud", max_allowed=1) as podcast: url = urls.soundcloud_track_list(podcast["broadcast_id"], self.client.soundcloud_client_id) httpretty.register_uri(httpretty.GET, url, body=json.dumps(soundcloud_two_tracks.DATA)) self.client.episode_sync(max_episode_sync=0) episode_list = self.client.episode_list(only_files=False) with test_utils.temp_audio_file() as mp3_body: test_utils.mock_mp3_download(episode_list[0]["download_url"], mp3_body) self.client.podcast_file_sync() episode_list = self.client.episode_list() self.assert_not_none(episode_list[0]["file_path"]) all_episodes = self.client.episode_list(only_files=False) self.assertTrue(len(all_episodes) > 1) self.client.database_cleanup() all_episodes = self.client.episode_list(only_files=False) self.assert_length(all_episodes, 1)
def test_episode_show(self): # check works with valid data with test_utils.temp_podcast(self.client, archive_type="rss", broadcast_url=True) as podcast: httpretty.register_uri(httpretty.GET, podcast["broadcast_id"], body=history_on_fire.DATA) self.client.episode_sync() episode_list = self.client.episode_list(only_files=False) self.assert_not_length(episode_list, 0) with test_utils.temp_audio_file() as mp3_body: test_utils.mock_mp3_download(episode_list[0]["download_url"], mp3_body) self.client.episode_download(episode_list[0]["id"]) # works as single episode = self.client.episode_show(episode_list[0]["id"])[0] self.assert_dictionary(episode) # works as list episode = self.client.episode_show([episode_list[0]["id"]])[0] self.assert_dictionary(episode)
def test_episode_sync_set_number_episodes(self): with test_utils.temp_podcast(self.client, archive_type="soundcloud", max_allowed=2) as podcast: page1_url = urls.soundcloud_track_list(podcast["broadcast_id"], self.client.soundcloud_client_id) httpretty.register_uri( httpretty.GET, page1_url, body=json.dumps(soundcloud_archive_page1.DATA), content_type="application/json", ) page2_url = soundcloud_archive_page1.DATA["next_href"] httpretty.register_uri( httpretty.GET, page2_url, body=json.dumps(soundcloud_archive_page2.DATA), content_type="application/json", ) self.client.episode_sync(max_episode_sync=3) episode_list = self.client.episode_list(only_files=False) self.assertEqual(len(episode_list), 3)
def test_download_youtube_skips_live(self): with test_utils.temp_podcast(self.client, archive_type="youtube", max_allowed=1) as podcast: url1 = urls.youtube_channel_get(podcast["broadcast_id"], self.client.google_api_key) with mock.patch("youtube_dl.YoutubeDL", side_effect=test_utils.youtube_mock_live): httpretty.register_uri( httpretty.GET, url1, body=json.dumps(youtube_archive1.DATA), content_type="application/json" ) url2 = urls.youtube_channel_get( podcast["broadcast_id"], self.client.google_api_key, page_token=youtube_archive1.DATA["nextPageToken"], ) httpretty.register_uri( httpretty.GET, url2, body=json.dumps(youtube_archive2.DATA), content_type="application/json" ) self.client.episode_sync() episode_list = self.client.episode_list(only_files=False) test_episode = episode_list[0] self.client.episode_download(test_episode["id"]) episode = self.client.episode_show(test_episode["id"])[0] self.assert_none(episode["file_path"])
def test_podcast_artist_name(self): with utils.temp_podcast(self.client, artist_name='foo') as podcast: self.assertEqual('foo', podcast['artist_name']) self.client.podcast_update(podcast['id'], artist_name='bar') podcast = self.client.podcast_show(podcast['id']) self.assertEqual('bar', podcast[0]['artist_name'])
def test_podcast_update_automatic_episode_download(self): with utils.temp_podcast(self.client) as podcast: self.client.podcast_update(podcast['id'], automatic_download=False) pod = self.client.podcast_show(podcast['id'])[0] self.assertFalse(pod['automatic_episode_download'])