How do I limit results from grabbag using BackReference syntax with FatFractal? - commonjs

It turns out I need to pass in a query to limit results returned from grabbag. I have a lot more songs in an events playlist (grabbag) than I do pictures with songs associated to them.
What would the query syntax to pass to grabBagGetAllForQuery? I basically need to look and see if the particular WNTrack in the grabbag has a back reference. If not then it hasn't been associated to a photo and shouldn't included in the returned result set.
// FFDL SNIPPET
#
#
# WNPhoto
#
# event: reference back to EVENT object
# owner: reference back to FFUser
# trackTag: reference back to TRACK
# accessGroup: FFUserGroup
# location: reference back to VENUE object
# image: BYTEARRAY
# previewImage: BYTEARRAY
# thumbnailImage: BYTEARRAY
#
CREATE OBJECTTYPE WNPhoto (event REFERENCE /Events, owner REFERENCE /UserProfiles, trackTag REFERENCE /Tracks, accessGroup REFERENCE /FFUserGroup, image BYTEARRAY, previewImage BYTEARRAY, thumbnailImage BYTEARRAY)
#
# WNTrack
#
# title: "My Way"
# artist: reference to an object in /Artists
# duration: 297
# albumCover: BLOB
# album: "The Main Event - Live"
#
CREATE OBJECTTYPE WNTrack (title STRING, artist REFERENCE /Artists, duration NUMERIC, albumCover BYTEARRAY, album STRING)

So - if I understand correctly, you want to exclude any items from the grabbag that do not have photos associated??
Using:
playlistForEvent = ff.grabBagGetAll(evnt.ffUrl, "playlist");
I think what I would do is get the photos as you are currently:
photosForEventsUri = "/ff/resources/Events/" + evnt.guid + "/photos";
photosForEvent = ff.getArrayFromUri(photosForEventsUri);
Then loop over and create an Array of tracks that are referenced.
for (var i=0;i< photosForEvent.length;i++) {
var track = ff.getReferredObject("trackTag", photosForEvent[i]);
playlistForEvent.push(track);
}

Related

Google Cloud Video Intelligence API in Python - Unable to run object tracking on multiple videos in a folder

I'm trying to run object tracking on a folder containing multiple videos. There are 5 videos in my bucket and following the documentation from here, it suggests using the wildcard (*) operator. However, when I run the entire script, only 1 video gets annotated and not the entire folder containing 5 videos. Also, response2.json does not get created as the output_uri in my GCS bucket.
To identify multiple videos, a video URI may include wildcards in the object-id. Supported wildcards: ' * ' to match 0 or more characters; ‘?’ to match 1 character.
https://googleapis.dev/python/videointelligence/latest/gapic/v1/types.html
Which is what I've done in my input_uri bit of the code:
gcs_uri = 'gs://video_intel/*'
If you check the screenshot, it should the bucket id name and shows multiple videos in the same folder.
Can anyone pls help with this question. Thanks.
Full script:
import os
os.environ['GOOGLE_APPLICATION_CREDENTIALS']='poc-video-intelligence-da5d4d52cb97.json'
"""Object tracking in a video stored on GCS."""
from google.cloud import videointelligence
video_client = videointelligence.VideoIntelligenceServiceClient()
features = [videointelligence.enums.Feature.OBJECT_TRACKING]
gcs_uri = 'gs://video_intel/*'
output_uri = 'gs://video_intel/response2.json'
operation = video_client.annotate_video(input_uri=gcs_uri, features=features, output_uri=output_uri)
print("\nProcessing video for object annotations.")
result = operation.result(timeout=300)
print("\nFinished processing.\n")
# The first result is retrieved because a single video was processed.
object_annotations = result.annotation_results[0].object_annotations
for object_annotation in object_annotations:
print("Entity description: {}".format(object_annotation.entity.description))
if object_annotation.entity.entity_id:
print("Entity id: {}".format(object_annotation.entity.entity_id))
print(
"Segment: {}s to {}s".format(
object_annotation.segment.start_time_offset.seconds
+ object_annotation.segment.start_time_offset.nanos / 1e9,
object_annotation.segment.end_time_offset.seconds
+ object_annotation.segment.end_time_offset.nanos / 1e9,
)
)
print("Confidence: {}".format(object_annotation.confidence))
# Here we print only the bounding box of the first frame in the segment
frame = object_annotation.frames[0]
box = frame.normalized_bounding_box
print(
"Time offset of the first frame: {}s".format(
frame.time_offset.seconds + frame.time_offset.nanos / 1e9
)
)
print("Bounding box position:")
print("\tleft : {}".format(box.left))
print("\ttop : {}".format(box.top))
print("\tright : {}".format(box.right))
print("\tbottom: {}".format(box.bottom))
print("\n")
please modify 'gcs_uri = 'gs://video_intel/'' to gcs_uri = 'gs://video_intel/.*'

Doctrine, how to add all objects of the relationship to the result of the QueryBuilder and actually show the content of the added objects?

I have the following structure in my database:
Each House has multiple Bedrooms and multiple Kitchens. Each Kitchen has multiple Cabinets.
Right now, I obtain all the cabinets based on a given Bedroom (I know it's weird). So I enter a Bedroom, It looks the House up, gets all the Kitchens associated with that House, then all Cabinets of those Kitchens. This is the code for it:
public function findCabinetsByBedroom(Bedroom $bedroom)
{
return $this->createQueryBuilder('cabinet')
->join('cabinet.kitchen', 'kitchen')
->join('kitchen.house', 'house')
->join('house.bedroom', 'bedroom')
->select('cabinet')
->andWhere('bedroom = : bedroom')
->setParameter('bedroom', $bedroom)
->getQuery()
->getResult(Query::HYDRATE_OBJECT);
}
I would like to extend my code to contain the Kitchen of each Cabinet and even the House. I managed to get the Kitchen by simply adding ->addSelect('kitchen') to my code. As so:
public function findCabinetsAndTheirKitchenByBedroom(Bedroom $bedroom)
{
return $this->createQueryBuilder('cabinet')
->join('cabinet.kitchen', 'kitchen')
->join('kitchen.house', 'house')
->join('house.bedroom', 'bedroom')
->select('cabinet')
->addSelect('kitchen')
->andWhere('bedroom = : bedroom')
->setParameter('bedroom', $bedroom)
->getQuery()
->getResult(Query::HYDRATE_OBJECT);
}
But trying to add the House information of the Kitchen doesn't work the same way and I guess it has to do with the fact that the Cabinets have no direct relationship with the House. Xdebug shows the following if I use the latest method (aka findCabinetsAndTheirKitchenByBedroom):
▼$cabinet = {array} [2]
▼0 = {App\Entity\Cabinet} [4]
id = 1
►time = {DateTime} [3]
productCategory = "someCat"
▼kitchen = {App\Entity\Kitchen} [3]
▼house = {Proxies\__CG__\App\Entity\House} [7]
lazyPropertiesDefaults = {array} [0]
►__initializer__ = {Closure} [3]
►__cloner__ = {Closure} [3]
__isInitialized__ = false
*App\Entity\House*bedroom = null
*App\Entity\House*id = 555
*App\Entity\House*name = null
id = 55
country = "US"
Opposes to this when I use the first one (aka findCabinetsByBedroom):
▼$cabinet = {array} [2]
▼0 = {App\Entity\Cabinet} [4]
id = 1
►time = {DateTime} [3]
productCategory = "someCat"
▼kitchen = {Proxies\__CG__\App\Entity\Kitchen} [7]
lazyPropertiesDefaults = {array} [0]
►__initializer__ = {Closure} [3]
►__cloner__ = {Closure} [3]
__isInitialized__ = false
*App\Entity\Kitchen*house = null
*App\Entity\Kitchen*id = 55
*App\Entity\Kitchen*country = null
So based on these result I concluded that addSelect indeed returned the Kitchen. And yes I checked the data in the database, it's the correct results. But how would I add the House information to the Cabinet?
One more issue, even though Xdebug shows the correct Kitchen info for each Cabinet, they're for some reason not returned when testing with POSTMAN or the browser. I get the following result:
{ "id": 1, "time": { "date": "2019-06-12 11:51:22.000000", "timezone_type": 3, "timezone": "UTC" }, "productCategory": "someCat", "kitchen": {} }
So it's empty for some reason. Any ideas how to display the information inside the Object Kitchen? I thought it had to do with it being a different object than Cabinet, but following this logic the content of time should have been empty as well since it's a DateTime object. So that can't be it but I have no clue why it's returned empty.
When using Doctrine, associations with other Entity objects are by default loaded "LAZY", see the docs about Extra lazy associations:
With Doctrine 2.1 a feature called Extra Lazy is introduced for associations. Associations are marked as Lazy by default, which means the whole collection object for an association is populated the first time its accessed. [..]
(I will say, documentation on the default fetching settings is very lacking, as this is the only spot (upgrade docs) which I could find where this is stated)
What this means: if you have something like the following Annotation, it means the relations will not be included until they're called, e.g. via a getObject() or getCollection()
/**
* #var Collection|Bathroom[]
* #ORM\OneToMany(targetEntity="Entity\Bathroom", mappedBy="house")
*/
private $bathrooms;
In this case, when you get your House object, an inspection of the object during execution (ie. with Xdebug) will show that the $house does have $bathrooms, however, each instance will show along the lines of:
{
id: 123,
location: null,
house: 2,
faucets: null,
shower: null,
__initialized__:false
}
This object's presence shows that Doctrine is aware of a Bathroom being associated with the House (hence the back 'n' forth ID's being set on the bi-directional relation, but no other properties set), however, the __initialized__:false indicated that Doctrine did not fetch the object. Hence: fetch="LAZY".
To get the associations with your get*() action, they must be set to fetch="EAGER", as shown here in the docs.
Whenever you query for an entity that has persistent associations and these associations are mapped as EAGER, they will automatically be loaded together with the entity being queried and is thus immediately available to your application.
To fix your issue:
Mark the associations you wish to return immediately as fetch="EAGER"
Extra:
Have a look at the Annotations Reference, specifically for OneToOne, OneToMany, ManyToOne and ManyToMany. Those references also show the available fetch options available for each association type.

Ember.js: How to get an array of model IDs from a corresponding array of model attributes

For a Tag model that I have in Ember-Data, I have 4 records in my store:
Tags:
id tag_name
1 Writing
2 Reading-Comprehension
3 Biology
4 Chemistry
In my code I have an array of tag_names, and I want to get a corresponding array of tag IDs. I'm having 2 problems:
My server is being queried even though I have these tags in my store. When I call store.find('tag', {tag_name: tag_name}), I didn't expect to need a call to the server. Here is all the code I'm using to attempt to create an array of IDs.
var self = this;
var tagsArray = ["Writing", "Reading-Comprehension", "Chemistry"];
var tagIdArr = []
tagsArray.forEach(function(tag_name) {
return self.store.find('tag', { tag_name: tag_name }).then(function(tag) {
tagIdArr.pushObject(tag.get('content').get('0').get('id'));
})
})
return tagIdArr;
When I console.log the output of the above code gives me an empty array object with length 0. Clicking on the caret next to the empty array shows three key-value pairs with the correct data. But the array is empty. I'm sure there is a simple explanation for this behavior, but I'm not sure why this is. I've used code similar to the above in other places successfully.
Find hits the server, but peek does not.
var tagsArray = ["Writing", "Reading-Comprehension", "Chemistry"];
return this.store.peekAll('tag').filter(function(tag){
return tagsArray.indexOf(tag) !== -1;
}).mapBy('id');
See: http://emberjs.com/blog/2015/06/18/ember-data-1-13-released.html#toc_reorganized-find-methods

Use metadata in filename when saving harbor input Liquidsoap

So I have an instance of Liquidsoap, which I am using to stream to an Icecast server.
I'd like to record any live broadcasts that take place automatically, which I am now doing and is working well.
What I'd like to do is use the metadata (specifically the songname) of the live show when creating the mp3 archive.
#!/usr/local/bin/liquidsoap
set("log.file",true)
set("log.file.path","/var/log/liquidsoap/radiostation.log")
set("log.stdout",true)
set("log.level",3)
#-------------------------------------
set("harbor.bind_addr","0.0.0.0")
#-------------------------------------
backup_playlist = playlist("/home/radio/playlists/playlist.pls",conservative=true,reload_mode="watch")
output.dummy(fallible=true,backup_playlist)
#-------------------------------------
live_dj = input.harbor(id="live",port=9000,password="XXX", "live")
date = '%m-%d-%Y'
time = '%H:%M:%S'
output.file(%mp3, "/var/www/recorded-shows/#{Title} - Recorded On #{date} At #{time}.mp3", live_dj, fallible=true)
#time_stamp = '%m-%d-%Y, %H:%M:%S'
#output.file(%mp3, "/var/www/recorded-shows/live_dj_#{time_stamp}.mp3", live_dj, fallible=true)
#-------------------------------------
on_fail = single("/home/radio/fallback/Enei -The Moment Feat DRS.mp3")
#-------------------------------------
source = fallback(track_sensitive=false,
[live_dj, backup_playlist, on_fail])
# We output the stream to icecast
output.icecast(%mp3,id="icecast",
mount="myradio.mp3",
host="localhost", password="XXX",
icy_metadata="true",description="cool radio",
url="http://myradio.fm",
source)
I have added #{title} where I would like my song title to appear, sadly though I am unable to get this populate.
My Dj's use BUTT and the show title is connected as part of their connection, so the data should be available pre recording.
Any advice is much appreciated!
This is far from being as easy as it seems.
The title metadata is dynamic, thus not available as a variable on script initialization
The filename argument of output.file is compiled when the script is initialized
A solution would consist in:
Defining a variable reference title to populate with live metadata
Output to a temporary file
Rename the file on close using on_close argument with output.file (in this case, we can just prepend the title)
This would give the following code (on a Linux box, change mv with ren on Windows):
date = '%m-%d-%Y'
time = '%H:%M:%S'
# Title is a reference
title = ref ""
# Populate with metadata
def get_title(m)
title := m['title']
end
live_dj = on_metadata(get_title,live_dj)
# Rename file on close
def on_close(filename)
# Generate new file name
new_filename = "#{path.dirname(filename)}/#{!title} - #{basename(filename)}"
# Rename file
system("mv '#{filename}' '#{new_filename}'")
end
output.file(on_close=on_close, %mp3, "/var/www/recorded-shows/Recorded On #{date} At #{time}.mp3", live_dj, fallible=true)
I tested a similar scenario and it works just well. Just beware that this will create a new file every time a DJ disconnects or updates the title. Also keep in mind that time stamps will be resolved by output.file.
This is based on the following example from a Liquidsoap dev: https://github.com/savonet/liquidsoap/issues/661#issuecomment-439935854)

Deleting hasMany record and saving with ember-data

I have a jsbin setup with my issue:
http://emberjs.jsbin.com/sovub/3/edit
From my example, in certain situations when I try to delete a subtitle and then save, I get the error:
Attempted to handle event `pushedData` on <App.Subtitle:ember563:7> while in state root.deleted.uncommitted.
If I delete the last subtitle then save, it's fine. But deleting the first subtitle, or deleting and adding new records then saving gives me the error message.
Is it because I'm manually setting the IDs for each subtitle during extractSingle, like so:
extractSingle: function(store, type, payload, id){
var list = payload.list
var nid = 6
// extra subtitles
var subs = list.subtitles
list.subtitles = []
subs.forEach(function(item){
item.id = nid++
list.subtitles.push(item.id)
item.list = list.id
})
// do the same for links
payload = { list: list, subtitle: subs, link: li}
return this._super(store, type, payload, id)
},
I've also noticed that the subtitles attribute of the payload in extractSingle doesn't contain the correct model whenever the error is thrown. Instead, it contains only the ID of the subtitle record.
// normally
id: "532",
subtitles: Array[2]
0: Class
__ember1403240151252: "ember562"
__ember1403240151252_meta: Object
// rest of data
1: Class
__ember1403240151252: "ember563"
__ember1403240151252_meta: Object
__nextSuper: undefined
// rest of data
// when error is thrown
id: "532",
subtitles: Array[1]
0: 6
length: 1
__proto__: Array[0]
I'm not really sure as how I should approach this, let alone resolve it. Any help would be appreciated.
I did some more research and found out about DS.RootState ( http://emberjs.com/api/data/classes/DS.RootState.html) which is related to the state root.deleted.uncommitted error I was getting.
To solve it, all I did was dematerialize the record after deleting it:
var model = this.get('model')
model.deleteRecord()
this.store.dematerializeRecord(model)
This removed the records indexes (and relationships?) so it was properly deleted.