示例#1
0
    def __init__(self):
        try:
            self.database = Database()
        except Exception as exception:
            print("Issue initializing database: ", exception)

        num_follows = int(os.getenv('NUM_DAILY_FOLLOWS', 100))

        self.bot = Bot(max_follows_per_day=num_follows,
                       max_unfollows_per_day=num_follows)
        self.bot.login()
示例#2
0
def upload_content():
    content_source_file = open('./utils/ig_users.txt')
    content_sources = content_source_file.read().split("\n")

    # captions
    caption_source_file = open('./utils/captions.csv', 'r')
    caption_source = caption_source_file.read().split(',\n')

    # hashtags
    hashtag_source_file = open('./utils/hashtags.csv', 'r')
    hashtag_source = hashtag_source_file.read().split(' ')

    # establish connection to the database
    database = None

    try:
        database = Database()
    except Exception as exception:
        print("Error Establishing Connection to Database:\n\n", exception)
        return

    # upload content sources to database
    for source in content_sources:
        database.insert_new_content_source(source)

    for caption in caption_source:
        database.insert_new_caption(caption)

    for hashtag in hashtag_source:
        database.insert_new_hashtag(hashtag)
示例#3
0
    def __init__(self) -> None:
        self.name = "Player"
        self.resources = ResourceBag()
        self.farm = Farm()
        self.farm.add_out_of_hive_bee(BeeWorker(parent=self))
        self.farm.add_out_of_hive_bee(BeeWorker(parent=self))
        self.farm.add_out_of_hive_bee(BeeWorker(parent=self))
        self.farm.add_out_of_hive_bee(BeeWorker(parent=self, level=2))
        # self.farm.add_out_of_hive_bee(BeeWorker(parent=self))
        self.farm.add_out_of_hive_bee(BeeWarrior(parent=self))
        self.farm.add_out_of_hive_bee(BeeWarrior(parent=self))
        # self.farm.add_out_of_hive_bee(BeeWarrior(parent=self))
        # self.farm.add_out_of_hive_bee(BeeWarrior(parent=self))

        self.farm.add_out_of_hive_bee(BeeQueen(parent=self))
        # self.farm.add_out_of_hive_bee(BeeQueen(parent=self))

        db = Database.get_instance()
        r = db.get_resource_by_id(3)
        r.value = 5
        self.resources.append(r)

        r = db.get_resource_by_id(4)
        r.value = 5
        self.resources.append(r)

        r = db.get_resource_by_id(5)
        r.value = 5
        self.resources.append(r)

        r = db.get_resource_by_id(2)
        r.value = 5
        self.resources.append(r)
示例#4
0
    def init_zones(self) -> None:
        bg_x, bg_y = self.__bg_map_rect.x, self.__bg_map_rect.y
        positions = [
            (bg_x + 20, bg_y + 75),
            (bg_x + 83, bg_y + 375),
            (bg_x + 488, bg_y + 183),
            (bg_x + 298, bg_y + 33),
            (bg_x + 415, bg_y + 465),
            # (bg_x + 285, bg_y + 214),
            (bg_x + 383, bg_y + 578)
        ]

        for i in range(6):
            zone = MapZone(self,
                           i + 1,
                           position=(positions[i][0], positions[i][1]))
            self.zones.append(zone)

        db = Database.get_instance()
        quest_data = db.get_all_quests()

        for qd in quest_data:
            quest = Quest(quest_template=qd, icon_offset=(bg_x, bg_y))
            if quest.quest_id in self.__completed_quests:
                self.zones[quest.zone - 1].add_quest(quest, True)

        self.path_points.clear()

        for z in self.zones:
            for qi in z.quest_icons:
                self.path_points.append(qi.get_rect().center)

        [z.lock() for z in self.zones]
        for i in self.__unlocked_zones:
            self.zones[i - 1].unlock()
示例#5
0
    def upgrade(self):
        self.upgrade_button.lock()

        bee = self.socket1.bee + self.socket2.bee

        if not bee:
            return

        remove_bag = ResourceBag()
        db = Database.get_instance()
        if not isinstance(self.socket1.bee, Bee):
            r1 = db.get_resource_by_id(self.socket1.bee.resource.r_id)
            r1.value = 1
            remove_bag.append(r1)

        if not isinstance(self.socket2.bee, Bee):
            r2 = db.get_resource_by_id(self.socket2.bee.resource.r_id)
            r2.value = 1
            remove_bag.append(r2)

        self.parent.player.resources -= remove_bag

        self.kill_bee(self.socket1)
        self.kill_bee(self.socket2)
        self.result_socket.unlock()
        self.result_socket.select()
        self.result_socket.bee = bee
        self.reload_bee_info()
示例#6
0
    def __init__(self, width: int, height: int) -> None:
        pygame.init()
        os.environ['SDL_VIDEO_CENTERED'] = '1'
        pygame.display.set_caption("Bee Island")
        self.__FPS = 60
        self.__size = self.width, self.height = width, height
        self.__screen = pygame.display.set_mode(self.size)
        icon = pygame.image.load("{0}/icon.ico".format(
            resource_path("res/images/")))
        pygame.display.set_icon(icon)

        Localization.set_locale(LocalList.RU)
        self.database = Database()

        self.main_player = Player()
        self.__scene_map = {
            "Map": MapScene(self, name="Map", player=self.main_player),
            "Farm": FarmScene(self, name="Farm", player=self.main_player),
            "Main": MainMenuScene(self, name="Main", player=self.main_player)
        }
        self.__current_scene = self.__scene_map["Map"]
        self.change_scene("Main")
        self.__prev_scene = None
        self.__done = False
        self.__clock = Clock()
示例#7
0
    def __init__(self, parent: Scene):
        Menu.__init__(self, parent=parent, bg_name="popup3")
        self._title_label = TextLabel(parent=self, text=self.parent.localization.get_string("hives"),
                                      position=self.position, font_size=16, bold=True)
        self._title_label.set_position(
            (self.position[0] + self._bg_image.get_rect().centerx - self._title_label.size[0] / 2 + 10,
             self.position[1] + 3)
        )

        self.hives_list_view = ListView(parent=self, size=(315, 410), item_padding=(8, 8), item_distance=(0, 15),
                                        position=(self.position[0] + 35, self.position[1] + 53))

        db = Database.get_instance()
        wax = db.get_resource_by_id(1)
        self.__wax_amount = 0

        for r in self.parent.player.resources.bag:
            if r.locale_name == wax.locale_name:
                self.__wax_amount = r.value

        self.hover_index = -1

        for h in self.parent.nest_group.buttons:
            if not h.hive:
                continue
            self.add_hive_to_list(h)

        self.parent.nest_group.stop_handle()
示例#8
0
def notify_daily_metrics():
    try:
        database = Database()
    except Exception as exception:
        print(exception)
        return

    # get current photo supply
    photo_supply = database.getPhotoSupply()

    # get current caption supply
    caption_supply = database.getCaptionSupply()

    # get follower supply
    follower_supply = database.getFollowerSupply()

    # get prev day follow successes
    num_days_ago = 1
    target_date = datetime.today() - timedelta(days=int(num_days_ago))
    target_year = target_date.year
    target_month = target_date.month
    target_day = target_date.day

    prev_day_follow_success = database.getPreviousDayFollowers(
        target_day, target_month, target_year)

    message = "Current Photo Supply:     " + str(photo_supply) + "</p>"
    message = message + "<p>Caption Supply:     " + str(
        caption_supply) + "</p>"
    message = message + "<p>Follower Supply:     " + str(
        follower_supply) + "</p>"
    message = message + "<p>Number of New Followers:     " + str(
        prev_day_follow_success) + "</p>"

    notify_email(message)
示例#9
0
 def __get_random_resource(self):
     db = Database.get_instance()
     r_id = random.choice(self.__items_ids)
     resource = db.get_resource_by_id(r_id)
     value = 0
     if r_id == 1:
         value = random.randint(5, 10)
     elif r_id == 2:
         value = random.randint(2, 6)
     elif r_id == 3:
         value = random.randint(1, 10)
     elif r_id == 4:
         value = random.randint(1, 5)
     elif r_id == 5:
         value = random.randint(1, 3)
     resource.value = value
     return resource
示例#10
0
    def change_lang(self, right: bool) -> None:
        if right:
            self.parent.main_window.change_lang(
                Localization.get_full_locale().get_next())
        else:
            self.parent.main_window.change_lang(
                Localization.get_full_locale().get_prev())

        self.current_lang_label.set_text(
            Localization.get_current_locale().upper())
        db = Database.get_instance()
        old_resources = []
        for r in self.parent.player.resources.bag:
            old_resources.append(r)
        self.parent.player.resources.bag.clear()

        for i in range(len(old_resources)):
            r = db.get_resource_by_id(old_resources[i].r_id)
            r.value = old_resources[i].value
            self.parent.player.resources.append(r)

        for b in itertools.chain(self.parent.player.farm.bees_from_all_hives,
                                 self.parent.player.farm.out_of_hive_bee_list):
            b.set_locale_to_bonus()
示例#11
0
def followee_retrieval():

    L = instaloader.Instaloader()
    request_count = 0

    # establish database connection
    database = None

    try:
        database = Database()
    except Exception as exception:
        print(
            "followee_retrieval: Error establishing a connection to the database..."
        )
        return

    print("Established Database...")

    # gets content sources from the database
    NUM_CONTENT_SOURCES = 1
    content_source_info = database.select_limit_content_source_rand(
        NUM_CONTENT_SOURCES)
    content_source_username = ""
    if (content_source_info):
        content_source_username = content_source_info[1]
    else:
        return

    # to store post information
    data_columns = [
        'username', 'user id', 'followers count', 'following count',
        'is private'
    ]
    new_followees = pd.DataFrame(columns=list(data_columns))

    total_new_followees = 100

    i = 0

    print("Getting profile information...")

    try:
        profile = instaloader.Profile.from_username(L.context,
                                                    content_source_username)
    except Exception as exception:
        print(exception)
        return

    request_count = request_rate_control(request_count)

    print("Getting Posts...")
    posts = profile.get_posts()
    request_count = request_rate_control(request_count)

    print("Posts received")

    #print("Number of Posts:", len(list(posts)))

    for post in posts:
        likers = (post.get_likes())
        request_count = request_rate_control(request_count)

        #print("Number of Likers: ", len(list(likers)))

        for liker in likers:
            request_count = request_rate_control(request_count)
            print(datetime.now(), "Username")
            username = liker.username
            print(datetime.now(), " User ID")
            user_id = liker.userid
            print(datetime.now(), "User Followers")
            followers_count = liker.followers
            print(datetime.now(), "User Followees")
            following_count = liker.followees
            print(datetime.now(), "User State")
            is_private = liker.is_private

            print(datetime.now(), "all liker information finished...")

            print("Inserting New Follower to Database...")
            database.insert_new_follower(user_id, username, followers_count,
                                         following_count, is_private)
            i += 1
            print("i:", i)

            if i >= total_new_followees:

                # Final Wait Period before the retrieval of content begins
                final_wait_period = 400

                print("Followee Retrieval Finished, waiting ",
                      final_wait_period, "seconds...")
                sleep(final_wait_period)
                return
示例#12
0
    def __init__(self, parent: Scene) -> None:
        Menu.__init__(self, parent=parent, bg_name="modify_popup1")
        self._title_label.set_text(
            text=self.parent.localization.get_string("modify_title"))
        self._title_label.set_position(
            (self.position[0] + self._bg_image.get_rect().centerx -
             self._title_label.size[0] / 2 + 10, self.position[1] + 3))
        self.socket_group = RadioGroup()
        self.socket1 = BeeSocket(parent=self,
                                 socket_type=BeeSocketType.ALL,
                                 group=self.socket_group,
                                 position=(self.position[0] + 102,
                                           self.position[1] + 135))
        self.socket1.set_image_by_state(ButtonState.SELECTED,
                                        "socket5_normal.png")
        self.dna_image = pygame.image.load("{0}/dna1.png".format(
            self._res_dir)).convert_alpha()
        self.dna_rect = self.dna_image.get_rect()
        self.dna_rect.x = self.socket1.position[0] + self.socket1.size[1] + 12
        self.dna_rect.y = self.socket1.get_rect(
        ).centery - self.dna_rect.height / 2
        self.socket2 = BeeSocket(
            parent=self,
            socket_type=BeeSocketType.ALL,
            group=self.socket_group,
            position=(self.dna_rect.x + self.dna_rect.width + 7,
                      self.socket1.position[1]))
        self.socket2.set_image_by_state(ButtonState.SELECTED,
                                        "socket5_normal.png")

        upgrade_label = TextLabel(
            parent=self,
            text=self.parent.localization.get_string("upgrade_button"),
            font_size=18)
        self.upgrade_button = TextButton(
            parent=self,
            normal_image_path="start_quest_btn_normal.png",
            text_label=upgrade_label,
            text_padding=(40, 4))
        self.upgrade_button.set_image_by_state(ButtonState.HOVERED,
                                               "start_quest_btn_hover.png")
        self.upgrade_button.set_image_by_state(ButtonState.LOCKED,
                                               "start_quest_btn_locked.png")
        self.upgrade_button.lock()
        self.upgrade_button.set_position(
            (self.socket1.position[0],
             self.socket2.position[1] + self.socket2.size[1] + 15))
        self.upgrade_button.add_action(
            {ButtonEventType.ON_CLICK_LB: lambda: self.upgrade()})

        self.result_socket = BeeSocket(parent=self,
                                       group=self.socket_group,
                                       position=(0, 0),
                                       socket_type=BeeSocketType.ALL)
        self.result_socket.set_image_by_state(ButtonState.SELECTED,
                                              "socket5_normal.png")
        self.result_socket.set_image_by_state(ButtonState.LOCKED,
                                              "socket3_normal.png")
        self.result_socket.lock()
        self.result_socket.set_position(
            (self.upgrade_button.get_rect().centerx -
             self.result_socket.size[1] / 2, self.upgrade_button.position[1] +
             self.upgrade_button.size[1] + 15))
        self.result_socket.add_action(
            {ButtonEventType.ON_CLICK_LB: lambda: self.pick_new_bee()})

        self.info_block_image = pygame.image.load(
            "{0}/modify_popup1_info.png".format(self._res_dir))
        self.info_block_rect = self.info_block_image.get_rect()
        self.info_text_label = TextLabel(
            parent=self,
            text=self.parent.localization.get_string("info_label"),
            font_size=14)

        self.info_block_rect.x = self.upgrade_button.position[
            0] + self.upgrade_button.size[0] + 95
        self.info_block_rect.y = self.position[1] + 71
        self.info_text_label.set_position(
            (self.info_block_rect.centerx - self.info_text_label.size[0] / 2,
             self.info_block_rect.y))

        name_label = MultilineTextLabel(parent=self,
                                        font_size=14,
                                        line_length=220,
                                        position=(self.info_block_rect.x + 25,
                                                  self.info_block_rect.y + 40))

        generation_label = TextLabel(
            parent=self,
            font_size=14,
            position=(name_label.position[0],
                      name_label.position[1] + name_label.size[1]))

        level_label = TextLabel(
            parent=self,
            font_size=14,
            position=(generation_label.position[0],
                      generation_label.position[1] + generation_label.size[1]))

        xp_label = TextLabel(
            parent=self,
            font_size=14,
            position=(level_label.position[0],
                      level_label.position[1] + level_label.size[1]))

        speed_label = TextLabel(
            parent=self,
            font_size=14,
            position=(xp_label.position[0],
                      xp_label.position[1] + xp_label.size[1]))

        hp_label = TextLabel(
            parent=self,
            font_size=14,
            position=(speed_label.position[0],
                      speed_label.position[1] + speed_label.size[1]))

        bonus_list_label = MultilineTextLabel(
            parent=self,
            font_size=14,
            line_length=220,
            position=(hp_label.position[0],
                      hp_label.position[1] + hp_label.size[1]))

        self.info_group = RenderGroup(parent=self,
                                      data={
                                          "b_name": name_label,
                                          "b_gen": generation_label,
                                          "b_level": level_label,
                                          "b_exp": xp_label,
                                          "b_speed": speed_label,
                                          "b_hp": hp_label,
                                          "b_bonus": bonus_list_label
                                      })

        self.bee_list_view = ListView(
            parent=self,
            size=(625, 253),
            padding=(30, 9),
            item_distance=(15, 15),
            position=(self.position[0] + 9, self.info_block_rect.y +
                      self.info_block_rect.height - 6))
        self.bee_list_view.set_image("{0}/modify_popup1_bee_list.png".format(
            self._res_dir))

        db = Database.get_instance()
        worker_dna_name = db.get_resource_by_id(3).locale_name
        warrior_dna_name = db.get_resource_by_id(4).locale_name
        queen_dna_name = db.get_resource_by_id(5).locale_name
        jelly_name = db.get_resource_by_id(2).locale_name

        dna_list = []
        for r in self.parent.player.resources.bag:
            if r.locale_name == worker_dna_name:
                for i in range(r.value):
                    dna_list.append(
                        DNAEntity(parent=self, dna_type="worker", r=r))
            if r.locale_name == warrior_dna_name:
                for i in range(r.value):
                    dna_list.append(
                        DNAEntity(parent=self, dna_type="warrior", r=r))
            if r.locale_name == queen_dna_name:
                for i in range(r.value):
                    dna_list.append(
                        DNAEntity(parent=self, dna_type="queen", r=r))
            if r.locale_name == jelly_name:
                for i in range(r.value):
                    dna_list.append(
                        DNAEntity(parent=self, dna_type="jelly", r=r))

        for b in itertools.chain(dna_list,
                                 self.parent.player.farm.out_of_hive_bee_list,
                                 self.parent.player.farm.bees_from_all_hives):
            self.add_bee_to_list(b)

        self.socket1.add_action(
            {ButtonEventType.ON_CLICK_LB: lambda: self.add_bee_to_socket()})
        self.socket1.add_action({
            ButtonEventType.ON_CLICK_RB:
            lambda: self.remove_bee_from_socket(self.socket1)
        })
        self.socket1.add_action({
            ButtonEventType.ON_HOVER_OUT:
            lambda: self.reload_bee_info(self.socket1.bee)
        })

        self.socket2.add_action(
            {ButtonEventType.ON_CLICK_LB: lambda: self.add_bee_to_socket()})
        self.socket2.add_action({
            ButtonEventType.ON_CLICK_RB:
            lambda: self.remove_bee_from_socket(self.socket2)
        })
        self.socket2.add_action({
            ButtonEventType.ON_HOVER_OUT:
            lambda: self.reload_bee_info(self.socket2.bee)
        })

        self.clear_bee_info()

        self.parent.nest_group.stop_handle()
示例#13
0
def content_retrieval():

    L = instaloader.Instaloader()
    database = None

    request_count = 0

    try:
        database = Database()
    except Exception as exception:
        print("Error Establishing Connection to Database:\n\n", exception)

    # get source IDs and usernames from database
    # returns format [content_source_id, content_source_username]
    content_source_info = database.select_content_sources()

    print("Number of Content Sources: ", len(content_source_info))

    j = 0

    # get posts from two days ago to yesterday
    since = datetime.now() + timedelta(days=-2)
    until = datetime.now() + timedelta(days=-1)

    # to store post information
    data_columns = ['username', 'likes_per_follower', 'post_id', 'url']
    new_posts = pd.DataFrame(columns=list(data_columns))

    i = 0  # number of posts currently found
    k = 0  # number of sources covered so far

    username_to_id = {}

    for source in content_source_info:

        k = k + 1
        print("\n\nStarting Content Source #", k)

        content_source_id = source[0]
        content_username = source[1]

        username_to_id[content_username] = content_source_id

        print("Gathering Profile...")
        try:
            profile = instaloader.Profile.from_username(
                L.context, content_username)
        except Exception as exception:
            print("Problem finding", content_username, "...")
            print(exception)
            continue

        request_count = request_rate_control(request_count)

        follower_count = profile.followers
        print("Profile: ", content_username)
        print("Follower Count: ", follower_count)
        request_count = request_rate_control(request_count)

        # check user's posts, save pictures
        print("Gathering Posts from Profile...")
        posts = profile.get_posts()
        request_count = request_rate_control(request_count)

        for post in takewhile(lambda p: p.date > since,
                              dropwhile(lambda p: p.date > until, posts)):
            if post.typename == 'GraphImage':
                new_posts.loc[i] = [
                    post.owner_username, post.likes / follower_count,
                    post.mediaid, post.url
                ]
                i = i + 1
                print("Viable post found, count is now ", i)
                request_count = request_rate_control(request_count)

            # instagram gets cranky when tired
            j = j + 1
            print("J: ", j)
            request_count = request_rate_control(request_count)

    # find top n new posts
    n = 5  # number of posts to save

    if (i < n):
        n = i

    new_posts = new_posts.sort_values('likes_per_follower', ascending=False)
    new_posts = new_posts.iloc[0:n, :]

    usernames = []
    photo_urls = []

    for username in new_posts["username"].values:
        usernames.append(username)

    for url in new_posts["url"].values:
        photo_urls.append(url)

    # get content_source_id and insert url, ID to database
    for username, url in zip(usernames, photo_urls):
        source_id = username_to_id[username]
        database.insert_new_photo(url, source_id)
示例#14
0
class InstagramBot(object):

    database = None
    bot = None

    def __init__(self):
        try:
            self.database = Database()
        except Exception as exception:
            print("Issue initializing database: ", exception)

        num_follows = int(os.getenv('NUM_DAILY_FOLLOWS', 100))

        self.bot = Bot(max_follows_per_day=num_follows,
                       max_unfollows_per_day=num_follows)
        self.bot.login()

    def setup_schedule(self):
        self.start_content_posting()
        self.start_follow_routine()

    def start_follow_routine(self):

        # looking back
        num_days = os.getenv('FOLLOW_WAIT_PERIOD_IN_DAYS', 2)
        num_days = 0
        past_requested_users_info = self.get_past_requests_to_follow(num_days)

        # get a list of the current users following the account
        current_followers_uuid = self.get_current_followers()

        num_unfollows = len(past_requested_users_info)
        unfollow_times = self.follow_routine_schedule(num_unfollows)

        # insert follow backs to follow_success in the database
        for follower_info in past_requested_users_info:
            follower_id = follower_info[0]
            instagram_uuid = follower_info[1]

            if (instagram_uuid in current_followers_uuid):
                self.database.insert_new_follower_success(follower_id)

            # unfollow each of the users that were requested n days ago
            unfollow_instance = unfollow_times.pop()

            schedule.every().day.at(unfollow_instance).do(
                self.unfollow_user, instagram_uuid)

        # Next Batch: Get number of follows for the day and list of users to follow
        NUM_DAILY_FOLLOWS = int(os.getenv('NUM_DAILY_FOLLOWS', 300))
        daily_follow_info = self.database.select_daily_follows(
            NUM_DAILY_FOLLOWS)

        # get an time at which to follow each of the users
        follow_instances = self.follow_routine_schedule(NUM_DAILY_FOLLOWS)

        # schedule a job to follow each user and record in the database that
        # they have been requested
        for account, instance in zip(daily_follow_info, follow_instances):
            follower_id = account[0]
            instagram_uuid = account[1]
            bot.follow(instagram_uuid)
            schedule.every().day.at(instance).do(self.follow_user, follower_id,
                                                 instagram_uuid)

    def follow_user(self, follower_id, instagram_uuid):
        bot.follow(instagram_uuid)
        self.database.insert_new_follower_request(follower_id)

        return schedule.CancelJob

    def unfollow_user(self, instagram_uuid):
        bot.unfollow(instagram_id)
        return schedule.CancelJob

    # returns [] with instagram_uuid's of current followers of the account
    def get_current_followers(self):
        current_followers = self.bot.followers

        return current_followers

    def get_past_requests_to_follow(self, num_days_ago):
        target_date = datetime.today() - timedelta(days=int(num_days_ago))
        target_year = target_date.year
        target_month = target_date.month
        target_day = target_date.day

        past_follow_info = self.database.select_past_follow_requests(
            target_day, target_month, target_year)

        return past_follow_info

    # returns list of str in the format 'HH:MM:SS'
    def follow_routine_schedule(self, num_instances):
        instances = []
        FOLLOW_PERIOD_START = os.getenv('FOLLOW_PERIOD_BEGIN', '05:00:00')
        period_start_parts = FOLLOW_PERIOD_START.split(":")
        hours_base = int(period_start_parts[0])
        minute_base = int(period_start_parts[1])
        seconds_base = int(period_start_parts[2])

        FOLLOW_PERIOD_IN_SEC = int(
            os.getenv('FOLLOW_PERIOD_LENGTH_IN_SEC', 25000))
        for i in range(0, num_instances):
            # generate
            num_seconds = random.randint(0, FOLLOW_PERIOD_IN_SEC)
            seconds_place = int(num_seconds % 60)
            minutes_place = int((num_seconds / 60) % 60)
            hours_place = int(((num_seconds / 60) / 60) % 60)

            # add new time places to start time base
            hours_place = hours_base + hours_place
            if (hours_place < 10):
                hours_place = "0" + str(hours_place)

            minutes_place = minute_base + minutes_place
            if (minutes_place < 10):
                minutes_place = "0" + str(minutes_place)

            seconds_place = seconds_base + seconds_place
            if (seconds_place < 10):
                seconds_place = "0" + str(seconds_place)

            current_instance = str(hours_place) + ":" + str(
                minutes_place) + ":" + str(seconds_place)
            instances.append(current_instance)

        return instances

    def start_content_posting(self):
        num_posts = self.decide_num_posts()

        post_times = []

        # select n post times
        for i in range(0, num_posts):
            post_time = self.get_post_time()

            # ensure that each new post time is not within min minutes of another post time
            MIN_POST_PERIOD: int = int(os.getenv('MIN_POST_PERIOD', 20))
            for x in post_times:

                current_post_time_compare = int(post_time.replace(":", ""))
                temp_post_time_compare = int(x.replace(":", ""))

                while (abs(current_post_time_compare - temp_post_time_compare)
                       < MIN_POST_PERIOD):
                    post_time = self.get_post_time()
                    current_post_time_compare = int(post_time.replace(":", ""))

            post_times.append(post_time)

        for post_time in post_times:

            # download selected photo, tuple in the form (photo_id, photo_url, content_source_id, photo_credits)
            photo_info = self.select_photo()
            photo_id = photo_info[0]
            photo_credits = photo_info[3]

            #(caption_id, caption)
            caption_info = self.get_caption()
            caption = caption_info[1]

            # select hashtags
            # array of tuples in the form (hashtag_id, hashtag)
            hashtag_info = self.get_hashtags()
            hashtag_string = ""
            for x in hashtag_info:
                hashtag_string = hashtag_string + x[1]

            # combine caption, credit, and hastags into txt file titled with photo id
            base_caption_file = open('./PostStaging/captionBase.txt', 'r')
            base_caption = base_caption_file.read()
            base_caption_file.close()

            final_caption = base_caption.replace("%c", caption)
            final_caption = final_caption.replace("%r", photo_credits)
            final_caption = final_caption.replace("%h", hashtag_string)

            final_caption_file_location = "./PostStaging/DailyContent/" + photo_id + ".txt"
            final_caption_file = open(final_caption_file_location, 'w')

            final_caption_file.write(final_caption)
            final_caption_file.close()

            # schedule job at post_time[i] with argument of photo_id
            schedule.every().day.at(post_time).do(self.post_photo, photo_info,
                                                  caption_info, hashtag_info)

    # number between 1 and n
    def decide_num_posts(self) -> int:
        # default number of posts a day is 3
        MAX_NUM_POSTS: int = int(os.getenv('NUM_DAILY_POSTS_MAX', 3))
        MIN_NUM_POSTS: int = int(os.getenv('NUM_DAILY_POSTS_MIN', 3))

        number_of_posts = random.randint(MIN_NUM_POSTS, MAX_NUM_POSTS)

        return number_of_posts

    # get urls from database
    # returns tuple in the form of (photo_id, photo_url, content_source_username)
    def select_photo(self):

        # tuple format (photo_id, photo_url, content_source_id, content_source_username)
        post_content = self.database.get_photo_for_posting()

        photo_id = ""
        photo_url = ""

        if (post_content == None):
            print("Couldn't find URLs")
        else:
            photo_id = post_content[0]
            photo_url = post_content[1]

        # attempt to download photo, if it fails get another photo and try again
        while (self.download_photo(photo_id, photo_url) == False):

            # upon failure of download, register issue in database table (url_invalid)
            issue_desc = "Problem downloading URL"
            self.database.insert_url_issue(photo_id, issue_desc)

            post_content = self.database.get_photo_for_posting()

            if (post_content == None):
                # raise alert
                print("Couldn't find any more URLs")
                return None

            photo_id = post_content[0]
            photo_url = post_content[1]

        return post_content

    # download photo via urls to staging directory
    def download_photo(self, photo_id, photo_url) -> bool:

        photo_location = "./PostStaging/DailyContent/" + photo_id + ".jpg"
        try:
            urllib.request.urlretrieve(photo_url, photo_location)
        except Exception as exception:
            print("Error with downloading URL: \n\n", exception)
            return False

        return True

    # get caption from database
    # returns tuple in the form of (caption_id, caption)
    def get_caption(self):
        caption_info = self.database.select_caption()
        if (caption_info):
            return caption_info

        return None

    # returns a string for the scheduled time for the post
    # format is 'HH:MM' where HH is in range 0-24
    def get_post_time(self) -> str:
        peak_post_base = os.getenv('PEAK_HOURS_START', '10:00')
        base_split = peak_post_base.split(':')

        hours_place = int(base_split[0])
        minutes_place = int(base_split[1])

        post_offset = self.decide_post_time_offset()
        hours_offset = int(post_offset / 60)
        minutes_offset = int(post_offset % 60)

        hours_place = hours_place + hours_offset
        minutes_place = minutes_place + minutes_offset

        # add leading 0 to minutes values less than 10
        if (minutes_place < 10):
            minutes_place = "0" + str(minutes_place)

        post_time = str(hours_place) + ":" + str(minutes_place) + ":00"

        return post_time

    # randomly decide on number between 0 and length of peak hours in minutes
    def decide_post_time_offset(self) -> int:
        duration_of_peak = int(os.getenv('PEAK_LEN_MIN', 540))

        return random.randint(0, duration_of_peak)

    def get_hashtags(self):
        hashtag_info = self.database.select_hashtag_cluster()
        if (hashtag_info):
            return hashtag_info

        return None

    # post photo via instabot
    def post_photo(self, photo_info, caption_info, hashtag_info):

        photo_id = photo_info[0]
        photo_address = "./PostStaging/DailyContent/" + photo_id + ".jpg"

        caption_file_address = "./PostStaging/DailyContent/" + photo_id + ".txt"
        caption_file = open(caption_file_address, 'r')
        caption = caption_file.read()

        # instabot does its thing here
        some_id = bot.upload_photo(photo_address, caption)

        instagram_id = "instagram_id (temp)"

        # add post information into post
        # returns the uuid for that specific post, used in hashtag_log
        # (uuid, instagram_id, timestamp, photo_id, content_source_id, caption_id)
        content_source_id = photo_info[2]
        caption_id = caption_info[0]

        post_id = self.database.insert_new_post(instagram_id, photo_id,
                                                content_source_id, caption_id)

        # add hashtag log information
        # (hashtag_id, photo_id)
        for hashtag in hashtag_info:
            hashtag_id = hashtag[0]
            insert_result = self.database.insert_new_hashtag_log(
                photo_id, hashtag_id)

            if (insert_result == False):
                print("Issue logging hashtag: ", hashtag_id, hashtag[1])

        return schedule.CancelJob